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);
通用参数导致 LambdaExpression
和 Compile
方法 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
,符合预期。
如果您想创建一个 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
我第一次探索表达式树。我有几个基本的疑问。
所以本质上,一个表达式只需要一个 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);
通用参数导致 LambdaExpression
和 Compile
方法 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
,符合预期。
如果您想创建一个 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