数组创建是否在每个foreach循环中发生?

时间:2014-09-05 18:55:17

标签: c# javascript php foreach

我发现自己这样做了:

string states = "this,that,theother";

foreach(string state in states.Split(','))
{

}

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

这个例子在c#中,但其他编程语言的表现有所不同吗?

PHP和JavaScript是否在每个foreach循环上拆分?

PHP :每次循环都会爆炸吗?

$states = "this,that,theother";

foreach(explode(',', $states) as $state)
{

}

这个问题并不重复,因为我要求的不仅仅是c#,它只是“重复问题”所指的语言。所有这些匿名的下选票将是Stack Overflow的死亡。

3 个答案:

答案 0 :(得分:1)

不,分裂发生一次。

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

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

在foreach()语句的开头,迭代的主题states.Split()将只被评估一次。在C#中,在编译时决定我们迭代什么类型的容器,并选择策略。编译器生成代码以将数组(或其他可枚举结果)返回到临时变量中,然后循环继续逐个访问数组中的第N个项。一旦范围被销毁," temp"容器是垃圾收集。

现在编译器并不总是使用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

答案 1 :(得分:1)

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

来自PHP manual

  

在每次迭代时,将分配当前元素的值   $value并且内部数组指针前进一个(所以在   下一次迭代,你将看到下一个元素。)

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

来自ES5注释reference

  

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

     
      
  1. O成为调用ToObject传递this值作为参数的结果。
  2.   

此处O表示正在迭代的对象;这个结果只计算一次。

答案 2 :(得分:0)

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