只为成功找方向,不为失败找借口

每天都不能停止前进的脚步
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

使用foreach来取代其它的循环结构

Posted on 2011-03-10 15:37  冰碟  阅读(377)  评论(0编辑  收藏  举报

摘自:Effective_CSharp 改善C#程序的50种方法

使用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.0C#编译器对循环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变量)做了检测。你把一个边界检测分成了两个。