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

时间:2015-05-23 01:12:13

标签: c# foreach

我有这个字符串数组。

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

foreach (string item in someArray)
  {
     Console.WriteLine(item);
  }

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

注意:使用VS 2012。

2 个答案:

答案 0 :(得分: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);
}

这在逻辑上等同于

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();
    }
}

如果您正在调试该扩展版本的代码,您会看到调试器突出显示MoveNextCurrent的调用。好吧,调试器以紧凑的形式做同样的事情;当MoveNext即将被调用时,调试器突出显示in,因为缺少任何更好的突出显示。在即将调用Current时,它会突出显示item。再一次,强调什么是更好的事情?

  

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

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

  

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

因为如果C#编译器知道foreach中的集合是一个数组,它实际上只是生成一个旧的for循环,而不是调用MoveNext和{{1}这一切。这样做通常会更快并且产生更少的收集压力,所以这是一个全面的胜利。

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

答案 1 :(得分: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”循环   不会改变。我们现在回复您的原始文章。