如何构建具有特定签名的表达式?

时间:2015-01-13 18:03:47

标签: c# lambda expression-trees

我正在尝试调用类型为Expression<Func<T, string>>的参数的方法,但我构建的表达式树不允许我调用该方法。这是一个简短但完整的程序,展示了这个问题:

using System;
using System.Linq.Expressions;

public class Test
{
    public string Name { get { return ""; } }

    public static void Main()
    {
        Foo<Test>();
    }

    static void Foo<T>()
    {
        var parameter = Expression.Parameter(typeof(T), "t");
        var property = Expression.Property(parameter, "Name");
        var lambda = Expression.Lambda(property, parameter);
        Bar<T>(lambda);
    }

    static void Bar<T>(Expression<Func<T, string>> expression) {}
}

错误:

error CS1503: Argument 1: cannot convert from
'System.Linq.Expressions.LambdaExpression' to 
'System.Linq.Expressions.Expression<System.Func<T, string>>'

如何将表达式树传递给方法?

2 个答案:

答案 0 :(得分:2)

您实际上已经在执行时构建了一个具有正确类型的表达式树(如果您只是不尝试调用该方法,并打印出该对象的类型,那么值lambda指的是)。但是,编译时类型lambda只是LambdaExpression,而不是Expression<Func<T, string>>。那是因为你正在使用Expression.Lambda的非泛型重载,它被设计为在在编译时知道所需的表达式树类型时使用。这在执行时做了正确的事情,但是不允许你以强类型的方式使用它。

幸运的是,你知道你想要产生的表达式树的类型,所以你只需要在调用Expression.Lambda的泛型重载时指定:

var lambda = Expression.Lambda<Func<T, string>>(property, parameter);

如果您构建的表达式树没有正确的类型,那将在执行时抛出异常,例如如果Value1属性类型错误。

答案 1 :(得分:1)

lambda的构建不正确。

var parameter = Expression.Parameter(typeof(T), "t");
var property = Expression.Property(parameter, "Value1");
var lambda = Expression.Lambda<Func<T, string>>(property, new[] { parameter });