Effective C#原则11:选择foreach循环

C#的foreach语句是从do,while,或者for循环语句变化而来的,它相对要好 一些,它可以为你的任何集合产生最好的迭代代码。它的定义依懒于.Net框架里 的集合接口,并且编译器会为实际的集合生成最好的代码。当你在集合上做迭代 时,可用使用foreach来取代其它的循环结构。检查下面的三个循环:

int [] foo = new int[100];
// Loop 1:
foreach ( int i in foo)
 Console.WriteLine( i.ToString( ));
// Loop 2:
for ( int index = 0; index < foo.Length; index++ )
 Console.WriteLine( foo[index].ToString( ));
// Loop 3:
int len = foo.Length;
for ( int index = 0; index < len; index++ )
 Console.WriteLine( foo[index].ToString( ));

对于 当前的C#编译器(版本1.1或者更高)而言,循环1是最好的。起码它的输入要少些 ,这会使你的个人开发效率提提升。(1.0的C#编译器对循环1而言要慢很多,所 以对于那个版本循环2是最好的。) 循环3,大多数C或者C++程序员会认为它是最 有效的,但它是最糟糕的。因为在循环外部取出了变量Length的值,从而阻碍了 JIT编译器将边界检测从循环中移出。

C#代码是安全的托管代码里运行的 。环境里的每一块内存,包括数据的索引,都是被监视的。稍微展开一下,循环 3的代码实际很像这样的:

// Loop 3, as generated by compiler:
int len = foo.Length;
for ( int index = 0; index < len; index++ )
{
 if ( index < foo.Length )
  Console.WriteLine( foo[index].ToString( ));
 else
   throw new IndexOutOfRangeException( );
}

C#的JIT编译 器跟你不一样,它试图帮你这样做了。你本想把Length属性提出到循环外面,却 使得编译做了更多的事情,从而也降低了速度。CLR要保证的内容之一就是:你 不能写出让变量访问不属于它自己内存的代码。在访问每一个实际的集合时,运 行时确保对每个集合的边界(不是len变量)做了检测。你把一个边界检测分成了 两个。

你还是要为循环的每一次迭代做数组做索引检测,而且是两次。 循环1和循环2要快一些的原因是因为,C#的JIT编译器可以验证数组的边界来确 保安全。任何循环变量不是数据的长度时,边界检测就会在每一次迭代中发生。 (译注:这里几次说到JIT编译器,它是指将IL代码编译成本地代码时的编译器, 而不是指将C#代码或者其它代码编译成IL代码时的编译器。其实我们可以用不安 全选项来迫使JIT不做这样的检测,从而使运行速度提高。)

原始的C#编 译器之所以对foreach以及数组产生很慢的代码,是因为涉及到了装箱。装箱会 在原则17中展开讨论。数组是安全的类型,现在的foreach可以为数组生成与其 它集合不同的IL代码。对于数组的这个版本,它不再使用IEnumerator接口,就 是这个接口须要装箱与拆箱。

IEnumerator it = foo.GetEnumerator( );
while( it.MoveNext( ))
{
 int i = (int) it.Current; // box and unbox here.
 Console.WriteLine( i.ToString( ) );
}

取而代之的是,foreach语句为数组生 成了这样的结构:

for ( int index = 0; index < foo.Length; index++ )
 Console.WriteLine( foo[index].ToString( ));

时间: 2024-09-15 16:41:09

Effective C#原则11:选择foreach循环的相关文章

运用c:foreach循环显示

惯例: 我是温浩然: 先说一下两种的区别,上图,改版之前. 后来的效果是: 很明显的,后来的是分组织结构显示的,这里用到的技术,就是C标签 先贴代码: <c:forEach items="${babyStages}" var="PagebabyStage" varStatus="status"> <c:if test="${status.index%10==0}"> <li data-projec

C++中实现foreach循环的示例

python,c#,java里面都有类似于foreach的结构,stl里面虽然有for_each这个函数,但是感觉使用还是太繁琐了一些,所以就自己实现了一个. 先来看看stl里面的for_each函数,官方文档上的原型如下: Function for_each (InputIterator first, InputIterator last, Function f); 示例代码如下: // for_each example #include <iostream> #include <al

详解JAVA中的for-each循环与迭代_java

在学习java中的collection时注意到,collection层次的根接口Collection实现了Iterable<T>接口(位于java.lang包中),实现这个接口允许对象成为 "foreach" 语句的目标,而此接口中的唯一方法,实现的就是返回一个在一组 T 类型的元素上进行迭代的迭代器. 一.迭代器Iterator 接口:Iterator<T> public interface Iterator<E>{ boolean hasNext

SSIS之Foreach循环容器用法

原文:SSIS之Foreach循环容器用法 要实现的业务:A数据库服务器上某库的T_GOODS_DECL的状态字段"Is_Delete"标记为"1"的时候删除B数据库服务器上对应库的T_GOODS_DECL表中的记录,二者的主键为"DECL_NO". 总体设计图,实现原理:上一步骤将结果集传递到循环容器中,容器逐行取数据来执行容器里面的SQL任务. 第一步:建立"获取标记为已删除的DECL_NO"执行SQL任务 选择正确的数据

“List&amp;amp;lt;T&amp;amp;gt;.Contains()&amp;amp;quot;的效率高,还是 foreach循环的效率高?

问题描述 "List<T>.Contains()"的效率高,还是foreach循环的效率高?判断一个对象是否存在于List<T>集合中,是使用"List<T>.Contains()"的效率高,还是foreach循环的效率高???if(DeviceList.Contains(dev)){returnDeviceList.Count;}foreach(IDeviceidinDeviceList){if(id==dev){returnD

SSIS从理论到实战再到应用(5) 流程控制之Foreach循环

上一期讲了For循环,Foreach循环相比而言要更复杂一点,里面涉及变量的类型,数据接收问题,下面我用一个简单的示例来演示Foreach循环容器: 假设我们有这样一个需求: 从数据库中取出一列数据,循环输出这列数据的每个值 一,拖入sql任务,定义一个Object类型的变量接收取到的数据 二,设置好接收变量

foreach循环遍历数组搞不懂执行顺序思路

问题描述 foreach循环遍历数组搞不懂执行顺序思路 搞不懂if判断那一块 最好有大神能给详细说明一下执行顺序 解决方案 这也没那么复杂http://blog.csdn.net/china_skag/article/details/6444727

遍历-求大神指点 关于java 的foreach循环问题

问题描述 求大神指点 关于java 的foreach循环问题 import java.util.Arrays; public class lianxi02 { public static void main(String[] args) { // 定义一个整型数组,保存成绩信息 int[] scores = { 89 72 64 58 93 }; // 对Arrays类对数组进行排序 Arrays.sort(scores); // 使用foreach遍历输出数组中的元素 for (int sco

Python基础三(选择,循环)

序 首先我们知道程序的执行有三种结构:顺序.选择.循环三种结构,而为了方便我们书写和多次利用我们就需要把一段代码封装器来,这就是方法.今天我就说的是程序的基本结构的格式和方法. 注:所有的程序都可以通过基本结构(顺序,选择,循环)书写出来. 流程结构 顺序结构语句 1:什么是流程控制语句 流程控制语句:可以控制程序的执行流程. 2:流程控制语句的分类 顺序结构 选择结构 循环结构 3:执行流程: 从上往下,依次执行. 选择结构语句 if 语法 if-else的使用格式 if 条件: 满足条件时要