12

我有一个表达式树,我通过使用 C# 中的表达式类解析 Xml 创建。看到这个问题

我的表达式树中只有加、减、除、乘、参数和和或。有没有办法将此 ExpressionTree 转换为可调用方法?...还是我必须手动发出 IL?

亲切的问候,

4

2 回答 2

12

您需要创建一个 lambda - 即

var lambda = Expression.Lambda<Func<float,int>>(body, param);
Func<float,int> method = lambda.Compile();
int v = method(1.0); // test

ParameterExpression其中“body”是涉及参数的表达式树(采用浮点数,返回一个 int) 。

您可能还会发现这个这个很有帮助。

于 2008-12-06T17:52:09.823 回答
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();
}

就个人而言,我的目标是第一种方法;它既简单又高效。这可能涉及在整个嵌套代码堆栈中传递原始参数,但就这样吧。我在某处有一些代码采用“调用”方法(复合),并将树重写为第一种方法(单一)-但它非常复杂且冗长。但对于实体框架(不支持 Expression.Invoke)非常有用。

于 2008-12-06T22:21:42.540 回答