C# 中的表达式树

Expression Trees in C#

我第一次探索表达式树。我有几个基本的疑问。

所以本质上,一个表达式只需要一个 lambda 表达式。然后我们可以将 lambda 表达式编译 () 为 MSIL 代码,后者又 return 是一个通用委托。我们可以按原样调用 returned 委托。我的理解正确吗?

如果这是我想要实现的目标:((10*5)+(9/4))

BinaryExpression b1 = Expression.MakeBinary(ExpressionType.Multiply, Expression.Constant(10), Expression.Constant(5));//(10*5)
BinaryExpression b2 = Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(9), Expression.Constant(4));//(9/4)
BinaryExpression b4 = Expression.MakeBinary(ExpressionType.Add, b1, b2);//((10*5)+(9/4))

所以在这一点上我们已经制作了 lambda expression body 。现在要把它变成 full lambda expression 我们需要调用

Console.WriteLine(Expression.Lambda<Func<int, int>>(b4).Compile());

我不明白这一部分。这也行不通。

为什么会这样 Func<int,int>

是不是内部表达式只接受 int 作为参数,而整个表达式 return 是一个 int?

显然这是行不通的。生成的 lambda 是什么样子的?

我得到了完整的图片?如何实现?

使用:

Console.WriteLine(Expression.Lambda<Func<int, int>>(b4).Compile());

你实际上用 Console.WriteLine(object) 重载打印它,它打印参数的 Type 的名称。

因为行:

Expression.Lambda<Func<int>>(b4).Compile();

仅编译 lambda 并且 为您提供 delegate - 而不是其调用的结果.

您需要调用已编译的 lambda 并仅打印结果:

Func<int> result = (Func<int>)Expression.Lambda<Func<int>>(b4).Compile();
Console.WriteLine(result());

另请注意,您尝试将 delegate 编译为 Func<int,int>,它采用 int 参数并提供 int 结果,但您的代码不需要参数,因此您需要使用 Func<int>.

您可以像这样创建您的 lambda 表达式:

LambdaExpression lb = Expression.Lambda(b4);

然后您可以将此表达式编译为委托:

Delegate dlg = lb.Compile();

并将此委托转换为 Func<int>:

Func<int> f = (Func<int>)dlg;

您可以照常使用它:

Console.WriteLine(f()); // 52

通用方法也适用。为什么你用Func<int,int>?您的表达式不需要任何输入,returns 一个 int:

Func<int> f = Expression.Lambda<Func<int>>(b4);

通用参数导致 LambdaExpressionCompile 方法 returns 一个 Func<int> 而不是您需要的 Delegate再次投射。

Expression.Lambda<Func<int, int>>(b4).Compile()

Func<int,int> 是采用单个 int 参数和 return 一个 int 的 lambda 的签名。您的 lambda 具有不同的签名。

Obviously this does not work.

您的 lambda 不带任何参数,因此您需要 Func<int>

How the generated lambda looks like?

生成的 lambda 是一个可调用对象。如果您想评估返回的表达式,请强制转换并调用它,如下所示:

var compiledLambda = (Func<int>)Expression.Lambda<Func<int>>(b4).Compile();
Console.WriteLine(compiledLambda());
//                              ^^

以上打印出 52,符合预期。

Demo 1.

如果您想创建一个 Func<int,int>,请在您的表达式中添加一个参数,例如使其成为 (p*5)+(9/4) 其中 p 是一个 int 参数:

ParameterExpression p = Expression.Parameter(typeof(int));
BinaryExpression b1 = Expression.MakeBinary(ExpressionType.Multiply, p, Expression.Constant(5));//(p*5)
BinaryExpression b2 = Expression.MakeBinary(ExpressionType.Divide, Expression.Constant(9), Expression.Constant(4));//(9/4)
BinaryExpression b4 = Expression.MakeBinary(ExpressionType.Add, b1, b2);
var compiledLambda = (Func<int,int>)Expression.Lambda<Func<int,int>>(b4, new[] {p}).Compile();
Console.WriteLine(compiledLambda(10)); // Prints 52
Console.WriteLine(compiledLambda(8));  // Prints 42

Demo 2.