如何将表达式树编译成可调用的方法,C#? [英] How do I compile an Expression Tree into a callable method, C#?

查看:161
本文介绍了如何将表达式树编译成可调用的方法,C#?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



请问,

解决方案

这是两种方法的一个例子。如果我错过了一些东西,或者想要更多的信息,只需让我知道。

  static void Main()
{
//尝试做x +(3 * x)

var single = BuildSingle< decimal>();
var composite = BuildComposite< decimal>();

Console.WriteLine({0} vs {1},单(13.2M),复合(13.2M));
}
//实用程序方法来获取3作为正确的类型,因为并不总是有一个int x T
static Expression ConvertConstant< TSource,TDestination>(TSource value)
{
return Expression.Convert(Expression.Constant(value,typeof(TSource)),typeof(TDestination));
}
//选项1:单个表达式树;这是最有效的
static Func< T,T> BuildSingle< T>()
{
var param = Expression.Parameter(typeof(T),x);
表达式body = Expression.Add(param,Expression.Multiply(
ConvertConstant< int,T>(3),param));
var lambda = Expression.Lambda< Func< T,T>(body,param);
return lambda.Compile();
}
//选项2:嵌套表达式树:
static Func< T,T> BuildComposite< T>()
{

//步骤1:执行乘法:
var paramInner = Expression.Parameter(typeof(T),inner);
表达式bodyInner = Expression.Multiply(
ConvertConstant< int,T>(3),paramInner);
var lambdaInner = Expression.Lambda(bodyInner,paramInner);

//步骤2:添加,调用现有树
var paramOuter = Expression.Parameter(typeof(T),outer);
表达式bodyOuter = Expression.Add(paramOuter,Expression.Invoke(lambdaInner,paramOuter));
var lambdaOuter = Expression.Lambda< Func< T,T>(bodyOuter,paramOuter);

return lambdaOuter.Compile();
}

个人而言,我将瞄准第一种方法;它更简单和更有效率。这可能涉及将原始参数传递到堆栈的嵌套代码,但是如此。我有一些代码在某个地方采用Invoke方法(复合),并重新编写树作为第一种方法(单) - 但它是相当复杂和漫长的。但对于实体框架(不支持Expression.Invoke)非常有用。


I have an expression tree I have created by parsing an Xml using the expression class in C#. See this question.

I only have Add, Subtract, Divide, Multiply, Parameters, And and Or in my Expression Tree. Is there a way to convert this ExpressionTree into a callable method? ...or do I have to emit the IL manually?

Kind regards,

解决方案

Here's an example of both approaches. If I have missed something, or you want more information, just let me know.

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();
}

Personally, I would aim towards the first method; it it both simpler and more efficient. This might involve passing the original parameter throughout a stack of nested code, but so be it. I have got some code somewhere that takes the "Invoke" approach (composite), and re-writes the tree as the first approach (single) - but it is quite complex and long. But very useful for Entity Framework (which doesn't support Expression.Invoke).

这篇关于如何将表达式树编译成可调用的方法,C#?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆