2017-04-07 120 views
1

考慮屬性表達式,如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(表達式)的結果調用。我無法弄清楚如何使用表達式作爲方法調用的參數。

+0

目前還不清楚你試圖達到什麼目的。方法'Foo'採用'string';你的'Expression'產生一個'object'。你想用什麼表達作爲參數來調用什麼方法? – dasblinkenlight

+1

如果我理解它,你應該只能使用Expression.Call(mi,Expression.Invoke(...))'? –

+0

這是挑戰的一部分。也許需要轉換。我很清楚自己想要達到的目標。對於給定的MyClass對象M,我想​​調用Foo(M.MyProperty)。輸入是由上面的'GetExpression'方法生成的表達式。 – l33t

回答

4

根據複雜性,有兩種方法可以做到這一點。在這種情況下,我們可以從重新使用這個內部表達式的參數 - 冒泡向外;我們通過丟棄舊的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); 

的另一種方式是在內部拉姆達使用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)是有用的 - 或者在哪裏,例如,您有多個不同參數實例的內部表達式。

+0

哇。保存了我的一天。謝謝! – l33t

+0

第二種方法對我來說實際上非常有用。謝謝。 – l33t

+0

@ l33t如果您想要,實際上還有第三個選項:使用自定義ExpressionVisitor將所有表達式替換爲另一個表達式 - 例如,將內部參數替換爲外部參數,但適用於任何表達式。如果您願意,可以提供示例。 –