数组的创建是否发生在每个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的死亡
不,两种语言每次都会拆分字符串(这太荒谬了)。
来自PHP手册:
在每次迭代中,当前元素的值被指定给
$value
,并且内部数组指针提前一(依此类推下一次迭代,您将看到下一个元素)。
请注意对内部数组指针的引用。如果每次迭代都对一个不同的数组进行操作,那么更改内部数组指针将毫无意义。
来自ES5注释参考:
当使用一个或两个参数调用
forEach
方法时采取以下步骤:
- 设
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
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