我第一次探索表达树。我有一些基本的疑虑。
基本上,表达式只接受lambda表达式。然后,我们可以将lambda表达式Compile()编译为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 expression body
。现在将它变为full lambda expression
我们需要调用
Console.WriteLine(Expression.Lambda<Func<int, int>>(b4).Compile());
我没有得到这一部分。这也行不通。
为何选择Func<int,int>
?
是否内部表达式只将int作为param,整个表达式将返回一个int?
显然这不起作用。生成的lambda是怎样的?
我正在全面了解情况?如何使这项工作?
答案 0 :(得分:6)
Expression.Lambda<Func<int, int>>(b4).Compile()
Func<int,int>
是lambdas的签名,它采用单个int
参数,并返回int
。你的lambda有不同的签名。
显然这不起作用。
您的lambda不接受任何参数,因此您需要Func<int>
。
生成的lambda是怎样的?
生成的lambda是一个可调用的对象。如果你想评估你得到的表达式,请投射并调用它,如下所示:
var compiledLambda = (Func<int>)Expression.Lambda<Func<int>>(b4).Compile();
Console.WriteLine(compiledLambda());
// ^^
以上打印52
,正如所料。
如果您想制作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
答案 1 :(得分: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);
通用参数会导致LambdaExpression
使用Compile
方法返回Func<int>
而不是Delegate
,您需要再次投射。
答案 2 :(得分: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>
。