数组的创建是否发生在每个foreach循环上

本文关键字:foreach 循环 创建 是否 数组 | 更新日期: 2023-09-27 18:20:45

我发现自己在做这件事:

string states = "this,that,theother";
foreach(string state in states.Split(','))
{
}

我想知道;states字符串是否在每个foreach循环上都被拆分?

这个例子在c#中,但其他编程语言的行为是否不同?

PHP和JavaScript在每个foreach循环上分开吗?

PHP:每个循环都会发生爆炸吗?

$states = "this,that,theother";
foreach(explode(',', $states) as $state)
{
}

这个问题不是重复的,因为我问的不仅仅是c#,c#只是"重复问题"所指的语言。所有这些匿名的投票都将导致Stack Overflow的死亡

数组的创建是否发生在每个foreach循环上

不,两种语言每次都会拆分字符串(这太荒谬了)。

来自PHP手册:

在每次迭代中,当前元素的值被指定给$value,并且内部数组指针提前一(依此类推下一次迭代,您将看到下一个元素)。

请注意对内部数组指针的引用。如果每次迭代都对一个不同的数组进行操作,那么更改内部数组指针将毫无意义。

来自ES5注释参考:

当使用一个或两个参数调用forEach方法时采取以下步骤:

  1. O是调用ToObject并传递this值作为参数的结果

这里O表示被迭代的对象;这个结果只计算了一次。

不,拆分只发生一次。

states.Split(',')返回一个数组。数组在.NET中实现IEnumerable

通常,.NET集合是实现IEnumerable或提供GetEnumerator()方法的向量、数组或其他集合,该方法返回具有属性Current和方法MoveNext()的枚举器对象。在某些情况下,编译器将生成使用GetEnumerator()的代码,在其他情况下,它将使用ldelem.ref发出简单的矢量指令,换句话说,将foreach转换为for循环。

在foreach()语句的开头,迭代的主题声明。Split(),将只计算一次。在C#中,在编译时,我们决定迭代什么样的容器,并选择一种策略。编译器生成代码,将数组(或其他可枚举结果)返回到临时变量中,然后循环继续逐个访问数组中的第N项。一旦作用域被销毁,"临时"容器就会被垃圾回收。

现在编译器并不总是使用IEnumerator。它可以将foreach()转换为for()循环。

考虑:

string states = "1,2,3";
foreach (var state in states.Split(','))
{
    Console.WriteLine(state);
}

样品MSIL:

IL_0017:  ldloc.s    CS$0$0000
IL_0019:  callvirt   instance string[] [mscorlib]System.String::Split(char[]) // happens once
IL_001e:  stloc.s    CS$6$0001    // <--- Here is where the temp array is stored, in CS$6$0001
IL_0020:  ldc.i4.0
IL_0021:  stloc.s    CS$7$0002    // load 0 into index
IL_0023:  br.s       IL_003a
IL_0025:  ldloc.s    CS$6$0001    // REPEAT - This is the top of the loop, note the Split is above this
IL_0027:  ldloc.s    CS$7$0002    // index iterator (like (for(int i = 0; i < array.Length; i++)
IL_0029:  ldelem.ref              // load the i-th element
IL_002a:  stloc.1
IL_002b:  nop
IL_002c:  ldloc.1
IL_002d:  call       void [mscorlib]System.Console::WriteLine(string)
IL_0032:  nop
IL_0033:  nop
IL_0034:  ldloc.s    CS$7$0002
IL_0036:  ldc.i4.1                 // add 1 into index
IL_0037:  add
IL_0038:  stloc.s    CS$7$0002
IL_003a:  ldloc.s    CS$7$0002
IL_003c:  ldloc.s    CS$6$0001
IL_003e:  ldlen
IL_003f:  conv.i4
IL_0040:  clt                      // compare i to array.Length
IL_0042:  stloc.s    CS$4$0003     // if i < array.Length
IL_0044:  ldloc.s    CS$4$0003     // then
IL_0046:  brtrue.s   IL_0025       // goto REPEAT (0025) for next iteration
C#中的

foreach只是一个语法糖。CLR/IL不支持类似的操作。foreach有两个版本,一个用于泛型,另一个用于支持旧的集合,但一般来说,它被扩展为这样的东西:

var enumerator = states.Split(',').GetEnumerator();
while (enumerator.MoveNext()) {
 string state = enumerator.Current;
 ...
}

点击此处查看更多详细信息:http://msdn.microsoft.com/en-us/library/aa664754(v=vs.71).aspx