2014-05-05 21 views
0

如何從System.Linq.Expressions.Expression創建樹(圖)?從表達式創建樹

我希望有一個結構的節點的圖(從表達式創建)像

MyNode 
{ 
    Expression _internalExpression = ... 
    MyNode Parent {get ...} 
    IEnumerable<MyNode> Children {get ...} 
} 

我想過從ExpressionVisitor推導,但我不知道如何從推斷父子關係 被調用的方法(Visit,VisitBinary等)。

更新: 也許我是不夠明確的 - 我希望有需要的Linq代碼(在表現形式,所以沒有大括號) 並給我回一個複合數據結構,我有分量如上所述(class MyNode {...})。

因此,它應該像這樣工作:

MyNode root = TreeCreator.FromExpression((x,y) => x + y);

的ExpressionVisitor遍歷表達式樹,並調用訪問方法遇到的每一個節點上 - 這是確定。不幸的是,它只需要單個參數 (表達式),所以我不知道它在哪個上下文(在哪個父項下)工作。如果它具有像Visit(Expression parent,Expression child)這樣的簽名,那麼通過重寫Visit方法可以很容易地構建MyNode節點的樹。

+2

如果你的對象實際上並不代表代碼表達式,那麼我會阻止你這樣做。這對你的類型的用戶來說會非常困惑,並且不會幫你解決那麼多問題。迭代一個類似於你剛剛提供的對象比迭代一個Expression表達式更容易。 – Servy

回答

2

這是容易遍歷在可比你在你的問題已經描述比它試圖穿越一個Expression樹的方式定義的圖表。如果你有一個具有代表其子項的IEnumerable,像這樣的對象:

class MyNode 
{ 
    MyNode Parent { get; private set; } 
    IEnumerable<MyNode> Children { get; private set; } 
} 

然後穿越它,你只需要幾行代碼:

public static IEnumerable<T> Traverse<T>(
    this IEnumerable<T> source 
    , Func<T, IEnumerable<T>> childrenSelector) 
{ 
    var stack = new Stack<T>(source); 
    while (stack.Any()) 
    { 
     var next = stack.Pop(); 
     yield return next; 
     foreach (var child in childrenSelector(next)) 
      stack.Push(child); 
    } 
} 

現在我們可以這樣寫:

IEnumerable<MyNode> nodes = GetNodesFromSomewhere(); 
var allNodesInTree = nodes.Traverse(node => node.Children); 

而這不需要試圖假裝這個節點圖表表示代碼表達式時的混亂。