产量返回延迟迭代问题

bfl*_*mi3 1 c# recursion iterator yield-return

我知道yield return会利用延迟加载,但我想知道我是否可能滥用迭代器或者很可能需要重构.

我的递归迭代器方法返回给定的所有祖先,PageNode包括它pageNode自己.

public class PageNodeIterator {
    //properties and constructor left out for brevity

    public IEnumerable<IPageNode> ancestorsOf(IPageNode pageNode) {
        if(pageNode == null) throw new ArgumentNullException(("pageNode"));

        if (pageNode.url != pageNodeService.rootUrl) {
            yield return pageNode;
            if (pageNode.parent != null)
                foreach (var node in ancestorsOf(pageNode.parent))
                    yield return node;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的调用中ancestorsOf,我正在调用方法然后反转返回的顺序IEnumerable,但是由于加载是延迟的,所以调用实际上不会发生,直到我调用ToArray()下一行并且pageNodeService在我的迭代器方法中的那个点为null并且抛出空引用异常.

ancestors = pageNodeIterator.ancestorsOf(currentNode).Reverse();
return ancestors.ToArray()[1].parent.children;
Run Code Online (Sandbox Code Playgroud)

所以,我想知道我哪里出错了.在这种情况下,如果有的话,使用迭代器的正确方法是什么?

我也想知道为什么pageNodeService在执行时为空.即使执行被延期,它还不应该保持价值吗?

Eri*_*ert 9

我不知道你的bug在哪里,而StackOverflow不是用于调试代码的服务; 我会通过在调试器中运行它并查找错误来解决您的问题.

但是,我将借此机会指出:

public IEnumerable<IPageNode> AncestorsOf(IPageNode pageNode) {
    if(pageNode == null) throw new ArgumentNullException(("pageNode"));
    // Do stuff that yields 
Run Code Online (Sandbox Code Playgroud)

稍有问题,因为块中的代码都没有运行,直到MoveNext第一次调用.换句话说,如果你这样做:

var seq = AncestorsOf(null); // Not thrown here!
using (var enumtor = seq.GetEnumerator())
{
    bool more = enumtor.MoveNext(); // Exception is thrown here!
Run Code Online (Sandbox Code Playgroud)

这对人们来说非常令人惊讶.而是像这样编写代码:

public IEnumerable<IPageNode> AncestorsOf(IPageNode pageNode) {
    if(pageNode == null) throw new ArgumentNullException(("pageNode"));
    return AncestorsOfIterator(pageNode);
}
private IEnumerable<IPageNode> AncestorsOfIterator(IPageNode pageNode)
{
    Debug.Assert(pageNode != null);
    // Do stuff that yields 
}
Run Code Online (Sandbox Code Playgroud)