2010-10-04 37 views
9

我已經經歷了和靠牆打我的頭,而現在搜索各種短語和關鍵字,但我找不到任何接近的答案所以我在這裏希望有人能提供一些線索。爲什麼我不能手動創建相同的表達式樹,我的直拉姆達產生

基本上我工作的跳水相當深入操縱,創造,並在C#4.0

修改表達式樹我碰到一個奇怪的異常來了,我不能做的

意義,如果我寫的是這樣的

Expression<Func<string,string>> InsertAString = (Insert) => "This " + (Insert == "" ? "" : Insert + " ") + "That"; 

當我調試,並期待在表達式樹,它看起來類似於這樣

  • F(節點類型=拉姆達)
    • 機構(節點類型=添加)
      • 左(節點類型=添加)
        • 左(節點類型=常數,值= 「此」)
        • 右(節點類型=條件)
          • IfFalse(節點類型=添加)
            • 左(節點類型=參數,NAME = 「插入」)
            • 右(節點類型=常數,值=「「)
          • IfTrue(節點類型=常數,值= 」「)
          • 測試(節點類型=等於)
            • 左(節點類型=參數,名稱= 「插入」)
            • 右(的NodeType =常數,值= 「」)
      • 右(的NodeType =常數,值= 「這」)
    • Paramerters(計數= 1)
      • 參數[0](節點類型=參數,名稱= 「插入」)

我可以叫

Console.WriteLine(InsertAString.Compile()("Is Something In-between")); 

和我說出去,因爲我希望

「這是在兩者之間那」

現在,如果我嘗試和重建使用表達式基類我碰到一個有趣的問題的靜態方法手動。(我的每一步分解成它自己的表達用於調試目的)以上

ParameterExpression Insert = Expression.Parameter(typeof(object), "Insert"); 
ConstantExpression This = Expression.Constant("This "); 
ConstantExpression That = Expression.Constant("That"); 
ConstantExpression Space = Expression.Constant(" "); 
ConstantExpression NoCharacter = Expression.Constant(""); 
BinaryExpression InsertPlusSpace = Expression.Add(Insert,Space); 
BinaryExpression InsertEqualsNoCharacter = Expression.Equal(Insert,NoCharacter); 
ConditionalExpression InsertPlusSpaceOrNothing = Expression.IfThenElse(InsertEqualsNoCharacter,NoCharacter,InsertPlusSpace); 
BinaryExpression ThisPlusInsertPlusSpaceOrNothing = Expression.Add(This,InsertPlusSpaceOrNothing); 
BinaryExpression ThisPlusInsertPlusSpaceOrNothingPlusThat = Expression.Add(ThisPlusInsertPlusSpaceOrNothing, That); 
Lambda Lambda = Expression.Lambda(ThisPlusInsertPlusSpaceOrNothingPlusThat, Middle); 
Expression<Func<string,string>> InsertAString = Lambda as Expression<Func<string,string>> 

即基於所生成的表達式樹的值重新作爲上述(至少具有相同的「看」相同的基本表達式樹)經過精細

一切步驟,直到你到達這條線

BinaryExpression InsertPlusSpace = Expression.Add(Insert,Space); 

編譯器會引發 出現InvalidOperationException是 未處理

二元運算符添加沒有被定義爲 'System.String' 和 'System.String'

現在,這是爲什麼?

爲什麼當我讓C#將Lambda轉換爲Expression時,顯然它使用Add NodeType,並且Types顯示顯示它肯定使用了System.String,但是當我嘗試手動執行時,它不會讓代碼繼續?

最後一點我甚至嘗試了以下內容:

BinaryExpression InsertPlusSpace = Expression.MakeBinary(ExpressionType.Add,Insert,Space); 

同樣的錯誤。

我很好奇爲什麼它似乎至少與我已經能夠找到迄今爲止表達式樹中的字符串連接工作,只有當不試圖建立一個手動添加常量和變量類型系統的表達式樹。串。

非常感謝大家的回覆。

回答

6

檢查文檔:「+」運算符實際上在String類中未定義。我想編譯器知道它意味着「連接字符串」,並將其轉換爲對Concat的調用。因此,當您撥打Expression.Add時,您需要指定實施操作的方法(在這種情況下,方法爲String.Concat)。

我反編譯與反射的表達,它提供了以下結果(格式化):

ParameterExpression expression2; 
Expression<Func<string, string>> expression = 
    Expression.Lambda<Func<string, string>>(
     Expression.Add(
      Expression.Add(
       Expression.Constant("This ", typeof(string)), 
       Expression.Condition(
        Expression.Equal(
         expression2 = Expression.Parameter(typeof(string), "Insert"), 
         Expression.Constant("", typeof(string)), 
         false, 
         (MethodInfo) methodof(string.op_Equality)), 
        Expression.Constant("", typeof(string)), 
        Expression.Add(
         expression2, 
         Expression.Constant(" ", typeof(string)), 
         (MethodInfo) methodof(string.Concat))), 
       (MethodInfo) methodof(string.Concat)), 
      Expression.Constant("That", typeof(string)), 
      (MethodInfo) methodof(string.Concat)), 
     new ParameterExpression[] { expression2 }); 

(注意:methodof是不是一個實際操作者,其正是反射器顯示爲ldtoken IL指令在C#。您必須使用反射來檢索該方法。)

+3

+1,但爲了清楚起見,一個簡潔的示例:Expression.Add(Expression.Constant(「a」),Expression.Constant(「b」),typeof(string ).GetMethod(「Concat」,new [] {typeof(string),typeof(string)}));' – 2010-10-04 19:33:00

+0

你知道粉筆這只是簡單的deb ug失明。 我再次運行它。從來沒有想過要看方法屬性8-O 然而在那裏它是System.String.Concat .... 感謝您的快速響應清理我:-) – TofuBug 2010-10-04 19:45:57