给定两个泛型类型变量,如何编译system.linq.expression树以将它们相乘?

时间:2012-10-30 19:27:15

标签: c# generics expression-trees

给定两个泛型类型变量,如何编译system.linq.expression树以将它们相乘?如果表达式抛出异常,如果两种类型之间没有有效的运算符*,则完全可以接受。

我选择了System.Linq.Expression,因为我记得在这里看到过这种方式,但对于如何做到这一点还不够。

感谢。

编辑:我选择编译Linq表达式以获得速度;这应该尽可能快。

3 个答案:

答案 0 :(得分:4)

您可以通过编写以下代码了解如何执行此操作:

Expression<Func<int, int, int>> multiply = 
    (left, right) => left * right;

将其编译成程序集并使用IL反汇编程序(如Reflector)查看C#编译器生成的代码。

使用给定的示例,C#编译器将生成如下内容:

var left = Expression.Parameter(typeof(int), "left");
var right = Expression.Parameter(typeof(int), "right");

var multiply = Expression.Lambda<Func<int, int, int>>(
    Expression.Multiply(left, right),
    new ParameterExpression[] { left, right });

这正是指定乘法表达式所需要做的。

当置于通用方法中时,它可能如下所示:

public static Func<T, T, T> BuildMultiplier<T>()
{
    var left = Expression.Parameter(typeof(T), "left");
    var right = Expression.Parameter(typeof(T), "right");

    var multiply = Expression.Lambda<Func<T, T, T>>(
        Expression.Multiply(left, right),
        new ParameterExpression[] { left, right });

    return multiply.Compile();
}

答案 1 :(得分:2)

尝试这样的事情:

var left = Expression.Parameter(typeof(T), "left");
var right = Expression.Parameter(typeof(T), "right");
var body = Expression.Multiply(left, right);
return Expression.Lambda<Func<T, T, TResult>>(body, left, right);

如果类型T没有有效的乘法运算符,Expression.Multiply行将抛出异常。

答案 2 :(得分:2)

  

我选择了System.Linq.Expression

请注意:还有另一种简单方法:

public static T Multiply<T>(T x, T y) {
    return ((dynamic)x) * y;
}

将工作(包括缓存)卸载到框架。另一个选项 - MiscUtil has generic operator support将其包装起来 - 可下载here