C# 中的表达式树

4

我第一次探索表达式树,有一些基本疑问。

本质上,一个表达式只需要一个lambda表达式。然后我们可以将lambda表达式编译为MSIL代码,进而返回一个通用的委托。我们可以直接调用返回的委托。我的理解是正确的吗?

如果是这样,这就是我想要实现的:((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表达式体。 现在要将其转换为完整的lambda表达式,我们需要调用

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

我不理解这部分。而且这也行不通。

为什么要用 Func<int,int>

是因为内部表达式只接受 int 参数,而整个表达式返回一个 int 吗?

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

我没有完全理解吗?怎样使其可行?


1
这个也不起作用。它做了什么?它给你一个错误吗?是什么错误? - Matt Burland
3个回答

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

Func<int,int>是用于接受单个int参数并返回int的lambda签名。您的lambda具有不同的签名。

显然这是行不通的。

您的lambda不接受任何参数,因此需要使用Func<int>

生成的lambda是什么样子的?

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

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

上面的代码输出了 52,符合预期。

演示 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.


4
您可以像这样创建您的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>”?您的表达式不需要输入,只返回单个“int”:
Func<int> f = Expression.Lambda<Func<int>>(b4);

使用泛型参数可以产生一个带有Compile方法的LambdaExpression,该方法返回一个Func<int>而不是您需要再次转换的Delegate


1
使用:

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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接