C#生成表达式<func <foo,object =“”>&gt;

时间:2016-10-25 08:28:32

标签: c# expression

我正在使用一个包含一个带有表达式参数x =&gt;的函数的库。 x.Name。

使用反射,我试图为Foo的每个属性调用它。这意味着我需要创建Expression&lt; Func&lt; Foo,object&gt;&gt;类型的表达式。对于每个房产。

我一直在阅读表达树,但没有任何内容涵盖这种情况。

foreach (var property in typeof(Foo).GetProperties())
{
    ParameterExpression pe = Expression.Parameter(typeof(Foo), "x");
    MemberExpression me = Expression.Property(pe, property.Name);

    Expression<Func<Foo, object>> expression = ...  // x => x.Name

    Bar(expression, property.Name);
}

解决:

foreach (var property in typeof(Foo).GetProperties())
{
    ParameterExpression pe = Expression.Parameter(typeof(Foo), "x");
    MemberExpression me = Expression.Property(pe, property.Name);

    var expression = (Expression<Func<Foo, object>>)
                  Expression.Lambda(Expression.Convert(me, typeof(object)), pe);

    Bar(expression, property.Name);
}

1 个答案:

答案 0 :(得分:1)

问题是你在编译时显然不知道类型Foo,否则你可以使用泛型Expression.Lambda重载创建一个lambda表达式并且没问题。 有一个重载Expression.Lambda将创建LambdaExpression并从您指定的表达式派生类型参数。这意味着,它将从参数表达式和您用作主体的成员表达式中扣除它。

在这两种实现中,都有一个问题。返回类型object是引用类型。但是,属性可能会返回值类型(例如int),这需要强制转换。通常,编译器会为您执行此操作。在这种情况下,你必须自己做。

private IEnumerable<LambdaExpression> CreateExpressions(Type fooType)
{
    foreach (var property in fooType.GetProperties())
    {
        ParameterExpression pe = Expression.Parameter(fooType, "x");
        MemberExpression me = Expression.Property(pe, property.Name);

        yield return Expression.Lambda(Expression.Convert(me, typeef(object)), pe);
    }
}

如果您在编译时知道类型Foo,则只需将通用参数Func<Foo, object>添加到Lambda方法即可。