2012-07-09 78 views
2

我必須實現一個表達式的調用圖,如Id = Id(Param);,這不是問題。調用圖IEnumerator

現在我必須實現一個枚舉器,它在滿足順序依賴關係的調用中一次列出所有拓撲順序中的一個。

這就是麻煩。

這是調用圖一個簡單的節點:

class CallGraphNode 
{ 
    private string name; 
    public List<CallGraphNode> dependents = new List<CallGraphNode>(); 
    public int dependencies; 
    private bool executed = false; 
    public bool Executable { get { return dependencies == 0; } } 
    public bool Executed { get { return executed; } set { executed = value; } } 

    public CallGraphNode(string name) 
    { 
     this.name = name; 
     dependencies = 0;  
    } 

    public override string ToString() 
    { 
     return name; 
    } 

    public void AddDependent(CallGraphNode n) 
    { 
     dependents.Add(n); 
    }   
} 

這是調用圖類本身:

class CallGraph : IEnumerable<List<CallGraphNode>> 
{ 
    public List<CallGraphNode> nodes = new List<CallGraphNode>(); 

    public void AddNode(CallGraphNode n) 
    { 
     nodes.Add(n); 
    } 

    public static void Show(IEnumerable<CallGraphNode> n) 
    { 
     foreach (CallGraphNode node in n) 
     { 
      Console.Write("{0} ", node); 
     } 
     Console.WriteLine(); 
    } 

    static IEnumerable<List<CallGraphNode>> EnumerateFunctions(List<CallGraphNode> executable, List<CallGraphNode> res) 
    { 
     if (executable.Count == 0) 
      yield return res; 
     else foreach (CallGraphNode n in executable) 
      { 
       if (!n.Executed) 
        res.Add(n); 
       List<CallGraphNode> next_executable = new List<CallGraphNode>(executable); 
       executable.Remove(n); 
       foreach (CallGraphNode m in n.dependents) 
        if (--m.dependencies == 0) 
         next_executable.Add(m); 
       foreach (List<CallGraphNode> others in EnumerateFunctions(next_executable, res)) 
        yield return others; 
       foreach (CallGraphNode m in n.dependents) 
        m.dependencies++; 
       if (!n.Executed) 
        res.Remove(n); 
      } 
    } 

    IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator() 
    { 
     List<CallGraphNode> executable = new List<CallGraphNode>(); 
     foreach (CallGraphNode n in nodes) 
      if (n.Executable || n.Executed) 
       executable.Add(n); 
     List<CallGraphNode> output = new List<CallGraphNode>(); 
     foreach (List<CallGraphNode> list in EnumerateFunctions(executable, output)) 
      yield return list; 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { throw new NotImplementedException(); } 
} 

現在的問題是,它只是將無法正常工作。當我嘗試創建一個IEnumerator併爲其分配GetEnumerator()返回值,我得到一個鑄造的錯誤,這就是誠實跟我想象試圖這樣做的時候:

IEnumerator<List<CallGraphNode>> lt = cg.GetEnumerator(); 

然後我試着:

System.Collections.Generic.List<CallGraphNode>.Enumerator en = cg.nodes.GetEnumerator(); 

這可行,但方法EnumerateFunctions永遠不會被調用,枚舉器只包含圖形節點的原始列表。

任何想法?

回答

5

問題是你正在實施IEnumerable<T>IEnumerable使用explicit interface implementation

你可能想改變這種聲明:

IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator() 

成爲一個 「正常」 的接口實現:

public IEnumerator<List<CallGraphNode>> GetEnumerator() 

或者,你可能堅持使用顯式接口實現,但使用:

IEnumerable<List<CallGraphNode>> sequence = cg; 
IEnumerator<List<CallGraphNode>> lt = sequence.GetEnumerator(); 
+0

我選擇了明確的實現方式ñ,它像一個魅力工作,謝謝。但EnumerateFunctions方法永遠不會被調用。很奇怪。 – Cancer 2012-07-09 20:22:33

+0

@ user1512923:你真的在迭代結果嗎?如果不是,那麼'GetEnumerator'方法中的* none *代碼將被調用。迭代器塊的一部分是代碼被懶惰地執行。 – 2012-07-09 21:33:46

+0

感謝Jon,你是對的,我設法讓它工作迭代結果!我認爲代碼本來會被調用的。非常感謝 :) – Cancer 2012-07-09 22:19:47