我知道,回报收益率采取延迟加载的优势,但我想知道如果我可能会被滥用或迭代器很可能需要重构。
我的递归迭代方法返回一个给定的所有祖先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;
}
}
}
在我的呼吁ancestorsOf
,我调用该方法,然后反向返回的顺序IEnumerable
,但由于装载延迟呼叫实际上并没有发生,直到我打电话ToArray()
的下一行,并在该点pageNodeService
在我的iterator方法是空和空引用异常被抛出。
ancestors = pageNodeIterator.ancestorsOf(currentNode).Reverse();
return ancestors.ToArray()[1].parent.children;
所以,我想知道我已经错了。 什么是在这种情况下使用迭代器的正确方法,如果在所有?
我也想知道为什么pageNodeService
是在执行的时间空。 即使是延迟执行不应该仍持有价值?
不是一个真正的答案...更多建议的一种替代实现消除递归。 太长张贴注释。
public IEnumerable<IPageNode> ancestorsOf(IPageNode pageNode) {
if(pageNode == null) throw new ArgumentNullException(("pageNode"));
Stack<IPageNode> stack = new Stack<IPageNode>();
stack.Push(pageNode);
while(stack.Any())
{
IPageNode n=stack.Pop();
if (n.url != pageNodeService.rootUrl) {
yield return n;
if(n.parent != null)
{
stack.Push(n.parent);
}
}
}
}
关于它的思考,你可以完全消除堆栈:
public IEnumerable<IPageNode> ancestorsOf(IPageNode pageNode) {
if(pageNode == null) throw new ArgumentNullException(("pageNode"));
IPageNode n = pageNode;
while(n != null && n.url != pageNodeService.rootUrl)
{
yield return n;
n = n.parent;
}
}
我不知道你的错误是,StackOverflow的和没有调试代码的服务; 我会在调试器中运行它,并寻找错误解决您的问题。
不过,我会借此机会指出的是这样的:
public IEnumerable<IPageNode> AncestorsOf(IPageNode pageNode) {
if(pageNode == null) throw new ArgumentNullException(("pageNode"));
// Do stuff that yields
稍微有问题的,因为没有在块中的代码的运行,直到MoveNext
被称为首次。 换句话说,如果你这样做:
var seq = AncestorsOf(null); // Not thrown here!
using (var enumtor = seq.GetEnumerator())
{
bool more = enumtor.MoveNext(); // Exception is thrown here!
这是非常令人吃惊的人。 相反,写你这样的代码:
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
}
它甚至意义在这个地方使用收益-通过调用反向以来, 所有的东西无论如何必须缓冲 ,所以你可以改为只返回祖先的完整列表。
添加起始节点这个迭代器外,如果你需要它。
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)
{
if (pageNode.parent != null )
{
yield return pageNode.parent;
yield return ancestorsOf(pageNode.parent);
}
}
}
}