C#ForEach循环(循环中的字符串声明)

Exp*_*ser 5 c# foreach

我有这个字符串数组的名称.

string[] someArray = { "Messi", "Ronaldo", "Bale", "Neymar", "Pele" };

foreach (string item in someArray)
  {
     Console.WriteLine(item);
  }
Run Code Online (Sandbox Code Playgroud)

当我在调试模式下运行foreach行上的断点并使用Step Into时,每次传递都会突出显示字符串项,就像它再次声明它一样.我想它应该只突出项目.这是否表示每次再次声明项目?

注意:使用VS 2012.

Eri*_*ert 10

这里的答案很微妙,因为这个问题(意外)不清楚.让我通过将它分成多个问题来澄清它.

每次循环时,循环变量是否在逻辑上重新声明foreach

正如另一个答案正确指出的那样,在C#5及更高版本中,是的.在C#1到4中,没有.

这种变化的可观察结果是什么?

在C#1中,没有办法区分它们.(并且规范实际上不清楚变量的声明位置.)

在C#2中,团队以匿名方法的形式添加了闭包.如果有多个闭包捕获C#2,3和4中的循环变量,它们都捕获相同的变量,并且它们都会在循环运行时看到它变异.这几乎不是你想要的.

在C#5中,我们采用了重大变化来说每次循环都会声明一个新的循环变量,因此每个闭包捕获一个不同的变量,因此不会观察到它的变化.

为什么每次循环时调试器都会返回循环变量声明?

通知您循环变量正在变异.如果你有

IEnumerable<string> someCollection = whatever;
foreach(string item in someCollection)
{
    Console.WriteLine(item);
}
Run Code Online (Sandbox Code Playgroud)

这在逻辑上等同于

IEnumerable<string> someCollection = whatever;
{
    IEnumerator<string> enumerator = someCollection.GetEnumerator();
    try
    {
        while( enumerator.MoveNext() )
        {
            string item;  // In C# 4.0 and before, this is outside the while
            item = enumerator.Current;
            {
                Console.WriteLine(item);
            }
        }
    }
    finally
    {
        if (enumerator != null)
            ((IDisposable)enumerator).Dispose();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你周围的代码是扩展版本的调试,你会看到调试突出的调用MoveNextCurrent.好吧,调试器以紧凑的形式做同样的事情; 什么时候MoveNext即将被调用调试器突出显示in,因为缺少任何更好的突出显示.什么时候Current即将被称为亮点item.再一次,强调什么是更好的事情?

因此,调试器突出显示变量的事实与变量是否重新声明无关?

正确.它会在Current即将被调用时突出显示变量,因为这将改变变量.它改变变量,无论它是C#5中的新变量,还是C#4中与之前相同的变量.

我注意到你改变了我的例子以使用通用序列而不是数组.你为什么这么做?

因为如果C#编译器知道在集合foreach是一个数组,它实际上只是产生一个良好的老式for循环,而不是调用MoveNext,并Current和所有.这样做通常会更快并且产生更少的收集压力,所以这是一个全面的胜利.

但是,C#团队希望调试体验无论如何都要一样.因此,代码生成器再次创建了步进点in- 此时生成for的循环变量被突变 - 再次,在foreach变量循环变量的代码上.这样调试体验是一致的.

  • @ExpertLoser:对于初学者来说,这确实是一个非常高级的主题.关于搞清楚工作原理的好奇心,我敢肯定!我正在为初学者C#程序员写一系列视频; 如果您对初学者难以理解的概念有任何见解,请随时在eric@lippert.com上留言. (2认同)

Chr*_*ain 8

这取决于您要定位的C#版本.在C#5中,它是一个新变量.在此之前,该变量被重用.

请参阅Eric Lippert的博客文章:http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

从帖子:

更新:我们正在进行重大改变.在C#5中,foreach的循环变量将在逻辑上位于循环内部,因此闭包每次都会关闭变量的新副本."for"循环不会改变.我们现在回复您的原始文章.