2

のような式の呼び出しグラフを実装する必要がありますがId = Id(Param);、それは問題ではありませんでした。

ここで、依存関係の順序を満たす呼び出しのすべてのトポロジー順序を一度に 1 つずつリストする列挙子を実装する必要があります。

そして、ここに問題があります。

これは、コール グラフの単純なノードです。

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が呼び出されることはなく、列挙子にはグラフ ノードの元のリストが含まれているだけです。

何か案は?

4

1 に答える 1

5

問題は、両方 IEnumerable<T>を実装し、明示的なインターフェイスの実装IEnumerableを使用していることです。

おそらく、この宣言を変更したいと思うでしょう:

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

「通常の」インターフェース実装になる:

public IEnumerator<List<CallGraphNode>> GetEnumerator()

または、明示的なインターフェイスの実装に固執することもできますが、次を使用します。

IEnumerable<List<CallGraphNode>> sequence = cg;
IEnumerator<List<CallGraphNode>> lt = sequence.GetEnumerator();
于 2012-07-09T19:45:20.563 に答える