foreach 是否在每次迭代时评估数组? [英] Does foreach evaluate the array at every iteration?
问题描述
我想创建一个跳过第一项的 foreach
.我在其他地方看到过,最简单的方法是使用 myCollection.Skip(1)
,但我有一个问题:
I want to create a foreach
which skips the first item. I've seen elsewhere that the easiest way to do this is to use myCollection.Skip(1)
, but I have a question:
关于 .Skip()
的 MSDN 文档描述它绕过序列中指定数量的元素,然后返回剩余的元素".这是否意味着调用
The MSDN documentation on .Skip()
describes that it "Bypasses a specified number of elements in a sequence and then returns the remaining elements." Does this mean that a call to
foreach(object i in myCollection.Skip(1))
{ ... }
程序是否必须在每次 foreach
迭代时执行 .Skip(1)
?还是 foreach
(有点像 switch
)不需要对数组进行多次计算?
Would the program have to perform .Skip(1)
every time the foreach
iterates? Or does foreach
(somewhat like a switch
) not require multiple evaluations of the array?
创建一个虚拟的 var _dummy = myCollection.Skip(1)
并迭代它会更有效吗?
Would it be more efficient to create a dummy var _dummy = myCollection.Skip(1)
and iterate on this instead?
推荐答案
我只是用这个来嘲笑你的代码
I just mocked your code with this
foreach(var v in Enumerable.Range(1,10).Skip(1))
v.Dump();
这是生成的 IL.
IL_0001: nop
IL_0002: ldc.i4.1
IL_0003: ldc.i4.s 0A
IL_0005: call System.Linq.Enumerable.Range
IL_000A: ldc.i4.1
IL_000B: call System.Linq.Enumerable.Skip//Call to Skip
IL_0010: callvirt System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator
IL_0015: stloc.1 // CS$5$0000
IL_0016: br.s IL_0026
IL_0018: ldloc.1 // CS$5$0000
IL_0019: callvirt System.Collections.Generic.IEnumerator<System.Int32>.get_Current
IL_001E: stloc.0 // v
IL_001F: ldloc.0 // v
IL_0020: call LINQPad.Extensions.Dump
IL_0025: pop
IL_0026: ldloc.1 // CS$5$0000
IL_0027: callvirt System.Collections.IEnumerator.MoveNext
IL_002C: stloc.2 // CS$4$0001
IL_002D: ldloc.2 // CS$4$0001
IL_002E: brtrue.s IL_0018
IL_0030: leave.s IL_0042
IL_0032: ldloc.1 // CS$5$0000
IL_0033: ldnull
IL_0034: ceq
IL_0036: stloc.2 // CS$4$0001
IL_0037: ldloc.2 // CS$4$0001
IL_0038: brtrue.s IL_0041
IL_003A: ldloc.1 // CS$5$0000
IL_003B: callvirt System.IDisposable.Dispose
IL_0040: nop
IL_0041: endfinally
如您所见,Skip
仅被调用一次.
As you can see Skip
is called only once.
等效的 c# 代码看起来像这样
Equivalent c# code would look something like this
IEnumerator<int> e = ((IEnumerable<int>)values).GetEnumerator();//Get the enumerator
try
{
int m;//This variable is here prior to c#5.0
while(e.MoveNext())
{//int m; is declared here starting from c#5.0
m = (int)(int)e.Current;
//Your code here
}
}
finally
{
if (e != null) ((IDisposable)e).Dispose();
}
考虑下面的代码,如果 foreach 在每次迭代时调用 VeryLongRunningMethodThatReturnsEnumerable
那么那将是一场噩梦.语言设计的巨大缺陷.幸运的是它不会那样做.
Consider the below code, If foreach calls VeryLongRunningMethodThatReturnsEnumerable
at each iteration then that would be nightmare. Huge flaw in the design of the language. Fortunately it doesn't do that.
foreach(var obj in VeryLongRunningMethodThatReturnsEnumerable())
{
//Do something with that obj
}
这篇关于foreach 是否在每次迭代时评估数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!