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

查看:46
本文介绍了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:

关于 .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屋!

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