在表达式树中使用属性表达式的值

时间:2017-04-07 14:50:54

标签: c# lambda expression-trees

考虑t => t.MyProperty之类的属性表达式,其中t的类型为MyClass。如何在我执行方法调用的新表达式中使用此属性表达式?

C#

class MyClass
{
    public string MyProperty { get; set; }
}

static void Foo(string foo)
{   
}

LambdaExpression GetExpression(Expression<Func<MyClass, object>> expr)
{
    return expr;
}

var myClass = new MyClass();
Foo(myClass.MyProperty);

现在有表达式......?

var expr = GetExpression(m => m.MyProperty);
var mi = typeof(Program).GetMethod(nameof(Program.Foo),
    BindingFlags.Public | BindingFlags.Static);

var myClass = new MyClass();
// Now what??
// var call = Expression.Call(mi, ???expr??);
// var invoke = Expression.Invoke(call, fooParameter);

我想使用expr的结果,并在Foo的调用中使用它。我知道我可以通过两个步骤完成此操作,我会调用expr.Compile().DynamicInvoke(myClass)来获取值,但这是我在这里要求的内容。

我想构建一个表达式,它接受一个属性getter表达式,然后执行对Foo(结果表达式)的调用。我无法弄清楚如何将表达式用作方法调用的参数。

1 个答案:

答案 0 :(得分:3)

根据复杂程度,有两种方法可以做到这一点。在这种情况下,我们可以重复使用来自内部表达式的参数 - 向外冒泡;我们通过丢弃旧的lambda来做到这一点,只需使用.Body.Parameters。例如:

var call = Expression.Lambda<Action<MyClass>>(
    Expression.Call(mi, expr.Body), expr.Parameters);

var myClass = new MyClass { MyProperty = "yay!" };
call.Compile().Invoke(myClass);

另一种方法是在内部lambda上使用Invoke

var outerParameter = Expression.Parameter(typeof(MyClass));
var typed = Expression.Convert(Expression.Invoke(expr, outerParameter), typeof(string));
var call = Expression.Lambda<Action<MyClass>>(Expression.Call(mi, typed), outerParameter);

第二种形式(Invoke)在您无法方便地控制两个地方的参数时很有用 - 或者,例如,您有多个内部表达式,其中不同的参数实例