为什么不延迟执行缓存迭代值?

GWL*_*osa 4 .net c# linq language-design

采取下面的代码,改编自这个问题:

//Borrowed from another question because its a simpler example of what happened to me.
IEnumerable<char> query = "Not what you might expect";
foreach(char vowel in "aeiou")
{
     query = query.Where(c => c != vowel);
}
foreach (char Output in query)
{
    System.Out.WriteLine(Output);
}
Run Code Online (Sandbox Code Playgroud)

这只会从查询字符集中删除"u".核心问题与第二个foreach c中的Where子句中的变量未被评估的事实有关.我的问题是:

1)为什么第一个foreach生成的委托不会捕获c构建的每个值?是否有一些情况我不知道哪里不是理想的行为?

2)如果它没有捕获值c,那么当查询实际运行时,该值是否仍然在第二个foreach的范围内?在我看来,如果它没有存储传入的变量的值,那么尝试解析第二个foreach的语句将失败,因为该变量c显然超出了范围.

我不明白为什么'在范围内使用我们在这个变量上看到的最后一个值'对于这种情况是一个很好的设计决策,并且希望有人可以对这个问题有所了解.

Mar*_*ell 7

它正在捕捉vowel; 尝试:

foreach(char vowel in "aeiou") {
     char tmp = vowel;
     query = query.Where(c => c != tmp);
}
Run Code Online (Sandbox Code Playgroud)

Jon 在这里有相关帖子的列表.

至于为什么...... foreach被定义为(在ECMA334v4§15.8.4中):

A foreach statement of the form `foreach (V v in x) embedded-statement` is then expanded to:

{
  E e = ((C)(x)).GetEnumerator();
  try {
    V v;
    while (e.MoveNext()) {
      v = (V)(T)e.Current;
      embedded-statement
    }
  }
  finally {
    … // Dispose e
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,V就是外面while-这意味着它捕获只有一次foreach.据我了解,在C#的团队,有时,怀疑这种变化的智慧(这是内部while在C#1.2规范,这将完全避免这个问题).也许它最终会改变,但现在它符合规范.