LINQ 表达式 API 是否没有提供创建变量的方法?

Does the LINQ Expression API offer no way to create a variable?

我想验证我的假设,即 LINQ 表达式 API 无法让我们创建表示创建局部变量的表达式。

换句话说,您不能创建表达式来表示:

int local;

因为是变量声明statement,而API不支持statement lambdas。由 LINQ 表达式 API(而不是委托实例)表示的 lambda 表达式可以使用的唯一状态是它接收的参数和它通过闭包接收的捕获变量。

我的假设(基于几个月的 LINQ 表达式实践 API)是否正确?

好吧,您可以使用 Expression.Block 来声明一个包含局部变量的块...

例如:

using System;
using System.Linq.Expressions;

public class Test
{    
    static void Main()
    {
        var x = Expression.Variable(typeof(int), "x");
        var assignment1 = Expression.Assign(x, Expression.Constant(1, typeof(int)));
        var assignment2 = Expression.Assign(x, Expression.Constant(2, typeof(int)));

        var block = Expression.Block(new[] { x }, new[] { assignment1, assignment2 });
    }
}

构建的表达式树等效于:

{
    int x;
    x = 1;
    x = 2;
}

C# 编译器不会在 lambda 表达式到表达式树的转换中使用此功能,据我所知,目前仍仅限于表达式 lambda。

错误。 Expression.Block 有一些重载可以做到这一点。

事实是您不能通过使用具有变量的 C# 编译器创建 lambda 表达式,但这是编译器的限制。

所以你不能

Expression<Func<int>> exp = () => {
    int v = 1;
    return v;
};

但你可以

var variable = Expression.Variable(typeof(int));
var lambda = Expression.Lambda<Func<int>>(
    Expression.Block(
        new[] { variable }, 
        Expression.Assign(variable, Expression.Constant(1)), 
        variable)); // With lambda expressions, there is an implicit
                    // return of the last value "loaded" on the stack

since that is a variable declaration statement, and the API does not support statement lambdas.

这在 .NET < 4.0 中是正确的。在 .NET 4.0 中,Microsoft 添加了 Expression 方法来构建方法主体中可能存在的几乎所有内容(缺少一些 "things",例如不安全代码 keywords/operators,此外还有原语,但没有像 forlock 这样可以构建在其他构造之上的复杂构造)。请注意,这些添加的内容中有 90% 与 LINQ-to-SQL/EF.

不兼容