我有这个字符串数组的名称.
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)
如果你周围的代码是扩展版本的调试,你会看到调试突出的调用MoveNext和Current.好吧,调试器以紧凑的形式做同样的事情; 什么时候MoveNext即将被调用调试器突出显示in,因为缺少任何更好的突出显示.什么时候Current即将被称为亮点item.再一次,强调什么是更好的事情?
因此,调试器突出显示变量的事实与变量是否重新声明无关?
正确.它会在Current即将被调用时突出显示变量,因为这将改变变量.它改变变量,无论它是C#5中的新变量,还是C#4中与之前相同的变量.
我注意到你改变了我的例子以使用通用序列而不是数组.你为什么这么做?
因为如果C#编译器知道在集合foreach是一个数组,它实际上只是产生一个良好的老式for循环,而不是调用MoveNext,并Current和所有.这样做通常会更快并且产生更少的收集压力,所以这是一个全面的胜利.
但是,C#团队希望调试体验无论如何都要一样.因此,代码生成器再次创建了步进点in- 此时生成for的循环变量被突变 - 再次,在foreach变量循环变量的代码上.这样调试体验是一致的.
这取决于您要定位的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"循环不会改变.我们现在回复您的原始文章.