2011-08-25 72 views
1

我有以下代码:约IEnumerable的<T>收集奇怪的问题

IEnumerable<TreeItem> rootTreeItems = BuildRootTreeItems(); 

BuildTreeView(rootTreeItems.ElementAt(0)); 

private static void BuildTreeView(TreeItem treeItem) 
    { 
     TreeItem subMenuTreeItem = new TreeItem(); 
     subMenuTreeItem.Header = "1"; 

     TreeItem subMenuTreeItem2 = new TreeItem(); 
     subMenuTreeItem.Header = "2"; 

     treeItem.TreeItems.Add(subMenuTreeItem); 
     treeItem.TreeItems.Add(subMenuTreeItem2); 
    } 

奇怪的是BuildTreeView返回后,rootTreeItems的第一个元素没有任何孩子节点,而它确实已经调试到时BuildTreeView方法。

这个问题让我困惑了很长时间,任何人有什么想法?非常感谢。

+0

'BuildRootTreeItems'返回一个LINQ表达式吗? – Gabe

+0

使用yield return来返回树项目,但使用的参数也是IEnumerable 类型 –

+0

是的,'yield return'也会导致这个问题。 – Gabe

回答

3

您很有可能在IEnumerable<>上遇到延期执行问题。需要记住的是,你的IEnumerable<TreeItem> rootTreeItems不是一个列表,而是每次被要求时都会得到一个列表的承诺。

所以,如果BuildRootTreeItems()创建使用LINQ查询IEnumerable<TreeItem>和使用.ToList().ToArray()然后在每次使用rootTreeItems你重新执行内部BuildRootTreeItems()

查询的时候它不强制执行查询调用rootTreeItems.ElementAt(0)将导致查询执行。如果稍后尝试再次呼叫rootTreeItems.ElementAt(0),则您正在重新执行查询并取回第一个TreeItem的不同实例。

尝试改变第一线,像这样:

IEnumerable<TreeItem> rootTreeItems = BuildRootTreeItems().ToArray(); 

这将强制执行,后来将防止重新执行。我敢打赌你的问题消失了。

+0

谢谢,男人,现在我更清楚发生了什么事情,ToList()帮助我解决问题,但是我仍然困惑的是我只打了rootTreeItems.ElementAt(0)一次,孩子怎么会不能添加 –

1

您的BuildRootTreeItems()方法返回IEnumerable接口的可能性是哪些元素是通过yield语句创建的,或者是Gabe在上面评论中提到的通过包含Select方法的Linq表达式链创建的IEnumerable的实现。

这可以导致重新创建IEnumerable的元素,每次访问枚举中的任何元素或使用Linq表达式或foreach语句通过它迭代。

0

我会去simplier:

这也可能发生,如果

A)TreeItem是值类型(结构)

B)TreeItem.TreeItems返回一个新的集合

但正确性很难从所提供的代码中扣除。

+0

1. TreeItem不是值类型 –

+0

2. TreeItems始终是在构造类时创建的同一个colloection –