c# - foreach 是否在每次迭代时评估数组?

标签 c# arrays foreach

我想创建一个跳过第一项的foreach。我在别处看到最简单的方法是使用 myCollection.Skip(1),但我有一个问题:

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

foreach(object i in myCollection.Skip(1))
{ ... }

程序是否必须在每次 foreach 迭代时执行 .Skip(1)?还是 foreach(有点像 switch)不需要对数组进行多次计算?

创建一个虚拟 var _dummy = myCollection.Skip(1) 并对其进行迭代是否会更有效?

最佳答案

我只是用这个来 mock 你的代码

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 仅被调用一次。

等效的 C# 代码看起来像这样

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 那么那将是一场噩梦。语言设计的巨大缺陷。幸运的是它不会那样做。

foreach(var obj in VeryLongRunningMethodThatReturnsEnumerable())
{
   //Do something with that obj
}

关于c# - foreach 是否在每次迭代时评估数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19867012/

相关文章:

c# - 如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext

javascript - php - 将数组从 php 传递到 jquery ajax,然后再次将相同的数组从 jquery 传递到 php

c - 将 char 存储在 char [] 中可以从指针生成整数而无需强制转换?

python - 为什么在迭代列表时从列表中删除项目会跳过所有其他项目

angularjs - 从内部 ng-repeat 访问 ng-repeat $index

java - 对于每个循环,将最后一个记录名称放入 TextView 中

c# - 如何在 C# Metro 应用程序的 AppBar 中聚焦文本框?

c# - 使用流从 C# 中的 mssql 中获取图像

c# - 将基类转换为派生类

c++ - 如何将整个 char 数组及其值传递给另一个函数?