2017-04-13 164 views
1

我有一個LambdaExpression,它是Expression<Func<T, string>>類型。代碼的設計目前不允許我繼續T這意味着我不得不使用較慢的DynamicInvoke,而不是Invoke將表達式<Func<T, U>>轉換爲表達式<Func <object,object >>

因爲我知道T的類型,所以我想將表達式轉換爲它接受T對象,允許我使用Invoke。怎麼樣?

這裏有一個良好的開端

class Program 
{ 
    class MyClass 
    { 
     public string MyProperty => "Foo"; 
    } 

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

    static void Main(string[] args) 
    { 
     var e1 = GetExpression(t => t.MyProperty); 
     var e2 = Expression.Lambda<Func<object, object>>(e1, e1.Parameters); 

     object myClass = new MyClass(); 
     string s1 = (string)e1.Compile().DynamicInvoke(myClass); 
     object s2 = e2.Compile().Invoke(myClass); 
    } 
} 
+0

你的問題不符合您的標題。您是否想要轉換'Func鍵'來'Func鍵<對象,對象>'轉換'Func鍵'來'Func鍵<對象,對象>',或轉換'表達>'來'表達'?這三個人都有不同的答案。 – hvd

+0

我可以編寫一些代碼來解決這個問題...只有一個問題...你想使用這些表達式實體框架/ LINQ to SQL,或者你想簡單地編譯這些表達式嗎?因爲改變'Expression'使它們成爲'Func '可能會使它們與EF不兼容。 – xanatos

+0

更新了問題。最後,我想編譯表達式以用作類型化委託,以便我可以使用Invoke()而不是DynamicInvoke()。我相信'Expression.Convert'是需要某種方式。 – l33t

回答

3

非表達版本會是什麼樣

Func<object, object> Convert<T>(Func<T, object> f) { 
    return o => f((T)o); 
} 

這是你需要在表達式中的版本做的一樣好東西。你是對的,Expression.Convert可以做到這一點。

Expression<Func<MyClass, object>> e1 = t => t.MyProperty; 
var p = Expression.Parameter(typeof(object)); 
var e2 = Expression.Lambda<Func<object, object>>(
    Expression.Invoke(e1, Expression.Convert(p, typeof(MyClass))), p); 

注:如@xanatos正確地指出,對於例如轉換Expression<Func<T, int>>Expression<Func<object, object>>,雖然C#支持的隱式裝箱轉換從intobject,表達式樹沒有。如果這與問題有關,則需要另一個Expression.Convert

+0

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

+0

@hvd我將再增加'Expression.Convert'從外部對象到'Expression.Invoke',在你有一個價值型的情況下(他們是不會隱盒裝) – xanatos

+0

@xanatos對於'表達>''到表達>',這確實可能有必要對於'表達>''來表達>',事實並非如此。我認爲'Expression >'已經被編輯出來,並且與這個問題無關,但我現在看到它沒有被編輯出來。也許你是對的。 – hvd

相關問題