是否评估的foreach在每次迭代的数组? [英] Does foreach evaluate the array at every iteration?

查看:185
本文介绍了是否评估的foreach在每次迭代的数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个的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:

MSDN文档.Skip()描述它跳过序列中的元素指定数量,然后返回剩余的元素。这是否意味着一个调用

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))
{ ... }

请问程序必须执行 .Skip(1)每次的foreach 迭代?还是的foreach (有点像开关)不要求阵列的多个评价?

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?

推荐答案

我只是嘲笑你的code本

I just mocked your code with this

foreach(var v in Enumerable.Range(1,10).Skip(1))
    v.Dump();

这里是IL产生的。

And here is the IL generated.

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  

正如你所看到跳过只调用一次。

等价的C#code会是这个样子。

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();
}

考虑低于code,如果通话的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆