无法进入返回IEnumerable<T>的方法?

32
我有一个返回IEnumerable的方法,就像这样...
public virtual IEnumerable<Page> ToPages(){
  // foreach logic
  yield return pages;

  // more foreach logic
  yield return otherPages;

  // etc
}

这种方法似乎可以以某种方式工作。但真正令人困惑的是,我无法进入它! 我在周围放置了调试器断点,但调试器只是直接通过它们!

有人知道为什么会发生这种情况吗?


一个提示 - 这可能是你收到“跨越非用户代码”的消息,看起来毫无意义的原因。当我寻找那个字符串时,花了我一段时间才找到这个问题。 - StayOnTarget
4个回答

41

在枚举该方法前,它不会被执行。

foo.ToPages().ToList() // will enumerate and your breakpoint will be hit.

这是一个很好的答案。IEnumerable<>总是意味着惰性执行。这是使用IEnumerable<T>与List<T>之间的核心区别之一。IEnumerable类型只会在需要迭代时返回指令。而List类型则会立即遍历集合并产生结果。 - Pete M
那个可行了...但是这也太奇怪了吧。为什么它会这样表现呢? - Ciel
@Ciel:我会发布一些链接,解释为什么它以这种方式工作。 - Eric Lippert
@Eric Lippert,谢谢。我正在添加一些资源,但是我的电池用完了。 - Talljoe

9
正如其他人所指出的那样,迭代器块的主体在迭代器实际移动之前不会被执行。仅仅创建迭代器除了创建它之外什么也不做。人们经常会感到困惑。
如果您对迭代器块的设计和实现感兴趣,这里有一些关于这个主题的好文章:
Raymond Chen:(基本要点的简短介绍)

Jon Skeet:(长的,深入的)

http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx

Eric Lippert(我):(高级场景和边缘案例)

http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/


5

0
尝试在yield上加一个break。这样应该就可以解决了。

你是什么意思?我在整个方法的每一行上都设置了断点,但它仍然没有进入其中。 - Ciel
“yield” 是函数返回的点,应该在那里中断。 - Gordon Thompson
应该是的,但事实并非如此。 - Ciel
4
"Yield" 是指 调用 MoveNext 返回的点。如果没有调用 MoveNext,那么它内部的断点显然不会被触发。 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接