2014-02-18 48 views
1

我的任務是根據幾個規則修改Expression。其中之一是刪除頂級轉換表達式,如果有這樣的,但只有頂級,而不是內部。我實現了流動類如何從表達式樹中只刪除頂層節點?

class RemoveConvertToObjectExpressionVisitor : ExpressionVisitor 
{ 
    protected override Expression VisitUnary(UnaryExpression node) 
    { 
     if (node.NodeType == ExpressionType.Convert || node.NodeType == ExpressionType.ConvertChecked) 
     { 
      return base.Visit(node.Operand); 
     } 
     return base.VisitUnary(node); 
    } 
} 

但它刪除所有的轉換表達式。看下面的例子(它只是一個行爲的樣本,在代碼本身沒什麼意義)。

class Model 
{ 
    public int Value { get; set; } 
} 

void Main() 
{ 
    Expression<Func<Model, object>> expression = m => m.Value + int.Parse(((object) "5").ToString()); 

    var visitor = new RemoveConvertToObjectExpressionVisitor(); 

    var result = visitor.Visit(expression.Body); 
} 

我想要的結果表現爲m.Value + Parse(Convert("5").ToString()),但它給m.Value + Parse("5".ToString())

回答

1

的原因,你的代碼刪除所有的轉換表現是訪問者的代碼不知道,如果它正在尋找在頂層或不。它只知道它是一個轉換表達式。

通過ExpressionVisitor實現來更改這個過程非常棘手,因爲如果您正在查看根表達式,您需要從訪問者內部進行分析。這樣做是定義一個bool變量topLevel,一開始將它設置爲true,然後將其設置爲false內所有VisitXYZ方法的一種方式:

class RemoveConvertToObjectExpressionVisitor : ExpressionVisitor { 
    private bool topLevel = true; 
    protected override Expression VisitUnary(UnaryExpression node) { 
     bool currentTop = topLevel; 
     topLevel = false; 
     if (currentTop && (node.NodeType == ExpressionType.Convert || node.NodeType == ExpressionType.ConvertChecked)) { 
      return base.Visit(node.Operand); 
     } 
     return base.VisitUnary(node); 
    } 
    /// You need to override all VisitXyz methods with the same code 
    protected override Visit...(...Expression node) { 
     topLevel = false; 
     return base.Visit(node); 
    } 
} 

這需要大量的代碼,甚至更多的努力從讀者瞭解發生了什麼。在頂級表達式上進行簡單類型檢查,並在出現轉換時抓取其操作數,會更好:

Expression<Func<Model, object>> expression = m => m.Value + int.Parse(((object) "5").ToString()); 

Expression result = expression.Body;  
bool isConvertTopNode = result.NodeType == ExpressionType.Convert || result.NodeType == ExpressionType.ConvertChecked; 
if (isConvertTopNode) 
{ 
    result = ((UnaryExpression)expression.Body).Operand; 
} 
+0

第二個建議似乎很好,但它不能編譯 - 給''不能轉換類型'System.Linq.Expressions.Expression >'改爲'System.Linq.Expressions.UnaryExpression'' –

+0

@PavelK改變後的答案應該更好。它使用你的訪客。但是,它假定您始終以頂級lambda表達式開始。 – dasblinkenlight

+0

現在,當我嘗試我的例子'var v = new RemoveConvertToObjectExpressionVisitor(); v.Visit(表達式);''我得到'ArgumentException''類型'System.Int32'的表達式不能用於返回類型'System.Object'。 –