一个for循环,2种写法;
for(int i=0;i<Array.Lengh;i++)
{
;
}和
int length=Array.Length;
for(int i=0;i<length;i++)
{
;
}
我向来就是采用第一种写法,但是最近有人批我。说第二种写法更好;
我觉得,第二种写法会分配栈内存,这不是多余吗?
Array.Length虽然多少也会消耗些性能

解决方案 »

  1.   

    看看高效编程c#。已经很明确了。第二种方法多此一举。除非你用的.net 1.1,那第二种会快一点。
      

  2.   

    Effective C# 原则11:选择foreach循环
    Item 11: Prefer foreach Loops 
    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( ));(译注:注意数组与集合的区别。数组是一次性分配的连续内存,集合是可以动态添加与修改的,一般用链表来实现。而对于C#里所支持的锯齿数组,则是一种折衷的处理。)foreach总能保证最好的代码。你不用操心哪种结构的循环有更高的效率:foreach和编译器为你代劳了。如果你并不满足于高效,例如还要有语言的交互。这个世界上有些人(是的,正是他们在使用其它的编程语言)坚定不移的认为数组的索引是从1开始的,而不是0。不管我们如何努力,我们也无法破除他们的这种习惯。.Net开发组已经尝试过。为此你不得不在C#这样写初始化代码,那就是数组从某个非0数值开始的。// Create a single dimension array.
    // Its range is [ 1 .. 5 ]
    Array test = Array.CreateInstance( typeof( int ),
    new int[ ]{ 5 }, new int[ ]{ 1 });这段代码应该足够让所有人感到畏惧了(译注:对我而言,确实有一点)。但有些人就是很顽固,无认你如何努力,他们会从1开始计数。很幸运,这是那些问题当中的一个,而你可以让编译器来“欺骗”。用foreach来对test数组进行迭代:
    foreach( int j in test )
      Console.WriteLine ( j );foreach语句知道如何检测数组的上下限,所以你应该这样做,而且这和for循环的速度是一样的,也不用管某人是采用那个做为下界。对于多维数组,foreach给了你同样的好处。假设你正在创建一个棋盘。你将会这样写两段代码:private Square[,] _theBoard = new Square[ 8, 8 ];// elsewhere in code:
    for ( int i = 0; i < _theBoard.GetLength( 0 ); i++ )
      for( int j = 0; j < _theBoard.GetLength( 1 ); j++ )
        _theBoard[ i, j ].PaintSquare( );取而代之的是,你可以这样简单的画这个棋盘:
    foreach( Square sq in _theBoard )
      sq.PaintSquare( );
    (译注:本人不赞成这样的方法。它隐藏了数组的行与列的逻辑关系。循环是以行优先的,如果你要的不是这个顺序,那么这种循环并不好。)foreach语句生成恰当的代码来迭代数组里所有维数的数据。如果将来你要创建一个3D的棋盘,foreach循环还是一样的工作,而另一个循环则要做这样的修改:
    for ( int i = 0; i < _theBoard.GetLength( 0 ); i++ )
      for( int j = 0; j < _theBoard.GetLength( 1 ); j++ )
        for( int k = 0; k < _theBoard.GetLength( 2 ); k++ )
          _theBoard[ i, j, k ].PaintSquare( );
    (译注:这样看上去虽然代码很多,但我觉得,只要是程序员都可以一眼看出这是个三维数组的循环,但是对于foreach,我看没人一眼可以看出来它在做什么! 个人理解。当然,这要看你怎样认识,这当然可以说是foreach的一个优点。)事实上,foreach循环还可以在每个维的下限不同的多维数组上工作(译注:也就是锯齿数组)。 我不想写这样的代码,即使是为了做例示。但当某人在某时写了这样的集合时,foreach可以胜任。foreach也给了你很大的伸缩性,当某时你发现须要修改数组里底层的数据结构时,它可以尽可能多的保证代码不做修改。我们从一个简单的数组来讨论这个问题:int [] foo = new int[100];假设后来某些时候,你发现它不具备数组类(array class)的一些功能,而你又正好要这些功能。你可能简单把一个数组修改为ArrayList:// Set the initial size:
    ArrayList foo = new ArrayList( 100 );任何用for循环的代码被破坏:
    int sum = 0;
    for ( int index = 0;
      // won't compile: ArrayList uses Count, not Length
      index < foo.Length;
      index++ )
      // won't compile: foo[ index ] is object, not int.
      sum += foo[ index ];然而,foreach循环可以根据所操作的对象不同,而自动编译成不同的代码来转化恰当的类型。什么也不用改。还不只是对标准的数组可以这样,对于其它任何的集合类型也同样可以用foreach.如果你的集合支持.Net环境下的规则,你的用户就可以用foreach来迭代你的数据类型。为了让foreach语句认为它是一个集合类型,一个类应该有多数属性中的一个:公开方法GetEnumerator()的实现可以构成一个集合类。明确的实现IEnumerable接口可以产生一个集合类。实现IEnumerator接口也可以实现一个集合类。foreach可以在任何一个上工作。foreach有一个好处就是关于资源管理。IEnumerable接口包含一个方法:GetEnumerator()。foreach语句是一个在可枚举的类型上生成下面的代码,优化过的:
    IEnumerator it = foo.GetEnumerator( ) as IEnumerator;
    using ( IDisposable disp = it as IDisposable )
    {
      while ( it.MoveNext( ))
      {
        int elem = ( int ) it.Current;
        sum += elem;
      }
    }如果断定枚举器实现了IDisposable接口,编译器可以自动优化代码为finally块。但对你而言,明白这一点很重要,无论如何,foreach生成了正确的代码。foreach是一个应用广泛的语句。它为数组的上下限自成正确的代码,迭代多维数组,强制转化为恰当的类型(使用最有效的结构),还有,这是最重要的,生成最有效的循环结构。这是迭代集合最有效的方法。这样,你写出的代码更持久(译注:就是不会因为错误而改动太多的代码),第一次写代码的时候更简洁。这对生产力是一个小的进步,随着时间的推移会累加起来。
      

  3.   

    定义int length就多余了
      

  4.   

    关键就这几句话
    对于当前的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不做这样的检测,从而使运行速度提高。)
      

  5.   

    http://www.cnblogs.com/WuCountry/archive/2007/02/27/658710.html
      

  6.   

    foreach我知道,但是有些是否还是要取foo.Length来判断循环是否遍历到最后一个元素了。
    int i =0;
    foreach(var item in foo)
    {
    if(++i ==foo.Length)
    {;}
    }
    这种情况还是要用到foo.Length
      

  7.   

    就是说这样的foreach循环里,也还是直接使用foo.length来的更高效了吧?
    而不是说先定义一个int length = foo.length
      

  8.   

    看4楼红字,说明为什么for中直接用foo.Length好的。foreach是顺带提一下的。
      

  9.   

    CLR要保证的内容之一就是:你不能写出让变量访问不属于它自己内存的代码。