我有一个表达式树,我是通过使用C#中的表达式类解析Xml而创建的。 See this question
我只在表达式树中添加,减去,除以,乘,参数,和或。 有没有办法将此ExpressionTree转换为可调用方法? ...或者我必须手动发射IL吗?
亲切的问候,
答案 0 :(得分:12)
你需要创建一个lambda - 即。
var lambda = Expression.Lambda<Func<float,int>>(body, param);
Func<float,int> method = lambda.Compile();
int v = method(1.0); // test
其中“body”是涉及ParameterExpression
param的表达式树(带浮点数,返回int)。
答案 1 :(得分:10)
以下是两种方法的示例。如果我遗漏了某些内容,或者您想了解更多信息,请告诉我。
static void Main()
{
// try to do "x + (3 * x)"
var single = BuildSingle<decimal>();
var composite = BuildComposite<decimal>();
Console.WriteLine("{0} vs {1}", single(13.2M), composite(13.2M));
}
// utility method to get the 3 as the correct type, since there is not always a "int x T"
static Expression ConvertConstant<TSource, TDestination>(TSource value)
{
return Expression.Convert(Expression.Constant(value, typeof(TSource)), typeof(TDestination));
}
// option 1: a single expression tree; this is the most efficient
static Func<T,T> BuildSingle<T>()
{
var param = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Add(param, Expression.Multiply(
ConvertConstant<int, T>(3), param));
var lambda = Expression.Lambda<Func<T, T>>(body, param);
return lambda.Compile();
}
// option 2: nested expression trees:
static Func<T, T> BuildComposite<T>()
{
// step 1: do the multiply:
var paramInner = Expression.Parameter(typeof(T), "inner");
Expression bodyInner = Expression.Multiply(
ConvertConstant<int, T>(3), paramInner);
var lambdaInner = Expression.Lambda(bodyInner, paramInner);
// step 2: do the add, invoking the existing tree
var paramOuter = Expression.Parameter(typeof(T), "outer");
Expression bodyOuter = Expression.Add(paramOuter, Expression.Invoke(lambdaInner, paramOuter));
var lambdaOuter = Expression.Lambda<Func<T, T>>(bodyOuter, paramOuter);
return lambdaOuter.Compile();
}
就个人而言,我会瞄准第一种方法;它既简单又有效。这可能涉及将原始参数传递到整个嵌套代码堆栈中,但也就是这样。我有一些代码采用“调用”方法(复合),并重新编写树作为第一种方法(单一) - 但它非常复杂和冗长。但对于Entity Framework(不支持Expression.Invoke)非常有用。