如何使用 yield break 中断递归 IEnumerable<T> 循环?

Dan*_*son 5 c# recursion ienumerable yield

我有以下方法效果很好,除了 yield break 语句只中断当前枚举器。我明白为什么会这样,但我对如何通过递归堆栈传播收益率突破感到空白。

    private static IEnumerable<Node> FindChildrenById(IEnumerable nodes, string parentText) {
        var en = nodes.GetEnumerator();
        var targetFound = false;
        while (en.MoveNext())  {
            var node = en.Current as Node;
            if (node != null) 
            {
                if (node.Parent == null && string.IsNullOrEmpty(parentText))
                {
                    //Returns the top level nodes if an empty parentIdis entered
                    targetFound = true;
                    yield return node;
                }
                else if (node.Parent != null && node.Parent.Text == parentText)
                {
                    //returns the nodes belonging to the parent
                    yield return node;
                }
                else
                {
                    //Recurse into the children to see whether one of these is the node to find
                    foreach (var nd in FindChildrenById(node.Nodes, parentText))
                    {
                        yield return nd;
                    }
                }
            }
        }
        if (targetFound)
        {
            yield break;
        }
    }
Run Code Online (Sandbox Code Playgroud)

因此,当我有以下节点并将“Top 2 a”作为 parentText 传递时...

Top 1
    Top 1 a
    Top 1 b
Top 2
    Top 2 a
       Top 2 aa
       Top 2 ab
       Top 2 ac
    Top 2 b
Top 3
    Top 3 a
    Top 3 b
Top 4
Run Code Online (Sandbox Code Playgroud)

......然后我得到了结果:

Top 2 aa
Top 2 ab
Top 2 ac
Run Code Online (Sandbox Code Playgroud)

这是正确的结果,但是,当我单步执行我的代码时,最外层循环继续处理前 3 名和前 4 名。如何跳出这个外循环?

Run*_* FS 3

如果我的代码正确,我想下面的代码可以解决您的问题

private static IEnumerable<Node> FindChildrenById(IEnumerable nodes, string parentText)
    {
        var result =
               (from node in nodes
                where (node.Parent == null && string.IsNullOrEmpty(parentText))
                      || (node.Parent != null && node.Parent.Text == parentText)
                select node).TakeWhile(node => !(node.Parent == null && string.IsNullOrEmpty(parentText)));
        return result;
    }
Run Code Online (Sandbox Code Playgroud)

它基于两种扩展方法(见下文)构建,并且应该只迭代直到满足您的目标找到条件

public static class IEnumerablExtensions
        {
            //Will iterate the graph in depth first order
            public static IEnumerable<TResult> Select<TResult>(this IEnumerable collection, Func<Node, TResult> selector)
            {
                foreach (var obj in collection)
                {
                    var node = obj as Node;
                    if (node != null)
                    {
                        yield return selector(node);
                        foreach (var n in node.Nodes.Select(selector))
                        {
                           yield return n;
                        }
                    }
                }
            }

        public static IEnumerable<Node> Where(this IEnumerable collection, Predicate<Node> pred)
        {
            foreach (var node in collection.Select(x => x)) //iterate the list in graph first order
            {
                if (pred(node))
                    yield return node;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

编辑:原始帖子中的 Select 方法存在错误(它没有迭代子项的子项),现已更正