我试图更熟悉表达树。
我创建了一个简单的开关表达式,如下所示:
var paramExp = Expression.Parameter(typeof(int));
Expression<Func<int>> defaultBodyExp = () => 4;
var switchBodyExp = Expression.Switch(paramExp, defaultBodyExp,
Expression.SwitchCase(defaultBodyExp, Expression.Constant(1)));
var func = Expression.Lambda<Func<int, int>>(switchBodyExp, paramExp).Compile();
int result = func(6);
但是,当尝试调用Compile
时,这会引发以下异常:
'System.Func`1 [System.Int32]'类型的表达式不能用于返回类型'System.Int32'
我可以通过以下方式让它发挥作用:
var paramExp = Expression.Parameter(typeof(int));
//Expression<Func<int>> defaultBodyExp = () => 4;
var defaultBodyMethodInfo = typeof(Program).GetMethod("DefaultBody");
var switchBodyExp = Expression.Switch(paramExp, Expression.Call(defaultBodyMethodInfo),
Expression.SwitchCase(Expression.Call(defaultBodyMethodInfo), Expression.Constant(1)));
var func = Expression.Lambda<Func<int, int>>(switchBodyExp, paramExp).Compile();
int result = func(6);
public static int DefaultBody()
{
return 4;
}
但我真的不确定为什么我的第一个例子不起作用,我很想知道如何正确地做到这一点所以我不必在我的第二个例子中声明一个方法。我是否需要像第二个例子那样进行某种调用调用?
我已经看了一些关于SO的其他类似答案,但我对Expression Trees有足够的新意见,我真的不确定他们是否回答了我的问题。
答案 0 :(得分:3)
lambda表达式 Expression<Func<int>>
只能在期望Func<int>
(如Enumerable.Select
)或Expression<Func<int>>
的地方直接使用(如{ {1}},但您需要将其包含在Expression.Quote
)中。
为了在你的情况下期望Queryable.Select
的地方使用它,需要将它转换为表示lambda表达式“执行”结果的表达式。我们将原始代码更改为
int
问题是Expression<Func<int>> defaultBodyLambda = () => 4;
var defaultBodyExp = ???;
应该是什么。
一种可能的(和一般的)解决方案是使用Expression.Invoke
方法:
???
或者,由于这个特殊的lambda表达式没有参数,我们可以简单地使用LambdaExpression.Body
属性:
var defaultBodyExp = Expression.Invoke(defaultBodyLambda);