如果我有一个如下所示的循环:
foreach (string pass in new string[] { "pass1", "pass2", "pass3" })
{
x = pass; //etc
}
最初是创建一次匿名字符串数组,还是每次传递都重新创建一次?
我相信前者,但同事们确信这是一个等待发生的错误,因为他们说foreach循环的每次迭代都会导致创建一个新的字符串数组。
VS反汇编代码表明我是对的,但我想确定。
我们正在考虑这个问题的原因是试图理解一个神秘的错误,它报告了一个集合在迭代时已被更改。
答案 0 :(得分:26)
根据Eric Lippert blog和specification,foreach循环是一个语法糖:
{
IEnumerator<string> e = ((IEnumerable<string>)new string[] { "pass1", "pass2", "pass3" }).GetEnumerator();
try
{
string pass; // OUTSIDE THE ACTUAL LOOP
while(e.MoveNext())
{
pass = (string)e.Current;
x = pass;
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}
}
如您所见,枚举器是在循环之前创建的。
@Rawling正确地指出,该数组对编译器的处理有点不同。 Foreach 循环已优化为 for 循环与数组。根据{{3}},您的C#5代码将如下所示:
string[] tempArray;
string[] array = new string[] { "pass1", "pass2", "pass3" };
tempArray = array;
for (string counter = 0; counter < tempArray.Length; counter++)
{
string pass = tempArray[counter];
x = pass;
}
初始化也只发生一次。
答案 1 :(得分:5)
如果您查看ILSpy,此代码将转换为类似
的内容string[] array = new string[]
{
"pass1",
"pass2",
"pass3"
};
for (int i = 0; i < array.Length; i++)
{
string pass = array[i];
}
是的,数组只创建一次。
然而,说服你的同事的最佳参考可能是C#规范的第8.8.4节,它基本上会告诉你LazyBerezovsky的答案。
答案 2 :(得分:2)
最初只创建一次。
我尝试了Ofer Zelig的建议(来自评论)
foreach (DateTime pass in new DateTime[] { DateTime.Now, DateTime.Now, DateTime.Now })
{
int x = pass.Second; //etc
}
并设置了一个断点。即使您在迭代之间等待,它也会为所有3次迭代提供相同的秒数。
答案 3 :(得分:1)
您可以测试它(有很多方法可以测试它,但这是一个选项):
string pass4 = "pass4";
foreach (string pass in new string[] { "pass1", "pass2", "pass3", pass4 })
{
pass4="pass5 - oops";
x = pass; //etc
}
然后看看会发生什么。
你会发现你是对的 - 它只执行了一次。
答案 4 :(得分:1)
如果重新创建数组,下面的示例应该回答问题。
int i = 0;
int last = 0;
foreach (int pass in new int[] { i++, i++, i++, i++, i++, i++, i++ })
{
if (pass != last)
{
throw new Exception("Array is reintialized!");
}
last++;
}
if (i > 7)
{
throw new Exception("Array is reintialized!");
}