【轉】編寫高品質代碼改善C#程式的157個建議——建議18:foreach不能代替for

來源:互聯網
上載者:User

標籤:style   exception   迭代器   ati   div   orm   items   索引   操作   

 

建議18:foreach不能代替for

上一個建議中提到了foreach的兩個優點:文法更簡單,預設調用Dispose方法,所有我們強烈建議在實際的代碼編寫中更多的使用foreach。但是,該建議也有不適合的情境。

foreach存在一個問題:它不支援迴圈時對集合進行增刪操作。比如,運行下面代碼會拋出異常InvalidOperationException:

            List<int> list=new List<int>(){0,1,2,3};            foreach (int item in list)            {                list.Remove(item);                Console.WriteLine(item);            }

取而代之的方法是使用for迴圈

            for (int i = 0; i < list.Count; i++)            {                list.Remove(list[i]);                Console.WriteLine(list[i]);            }

foreach迴圈使用了迭代器進行集合的遍曆,它在FCL提供的跌代替內部維護了一個對集合版本的控制。那麼什麼是集合版本?簡單來說,其實它就是一個整形的變數,任何對集合的增刪操作都會使版本號碼加1.foreach會調用MoveNext方法來遍曆元素,在MoveNext方法內部會進行版本號碼的檢測,一旦檢測到版本號碼有變動,就會拋出InvalidOperationException異常。

如果使用for迴圈就不會帶來這樣的問題。for直接使用索引器,它不對集合版本號碼進行判斷,所以不會存在以為集合的變動而帶來的異常(當然,超出索引長度這種異常情況除外)。

由於for迴圈和foreach迴圈實現上有所不同(前者索引器,後者迭代器),因此關於兩者效能上的爭議從來沒有停止過。但是,即使有爭議,雙方都承認兩者在時間和記憶體上有損耗,尤其是針對泛型集合時,兩者的損耗是在同一個數量層級上的。

以類型List<T>為例,索引器如下所示:

[__DynamicallyInvokable]public T this[int index]{    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]    get    {        if (index >= this._size)        {            ThrowHelper.ThrowArgumentOutOfRangeException();        }        return this._items[index];    }    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable]    set    {        if (index >= this._size)        {            ThrowHelper.ThrowArgumentOutOfRangeException();        }        this._items[index] = value;        this._version++;    }}

迭代器如下所示:

[__DynamicallyInvokable]public bool MoveNext(){    List<T> list = this.list;    if ((this.version == list._version) && (this.index < list._size))    {        this.current = list._items[this.index];        this.index++;        return true;    }    return this.MoveNextRare();}
[__DynamicallyInvokable]public T Current{    [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]    get    {        return this.current;    }} 

可以看到,List<T>類內部維護著一個泛型數組:

private T[] _items;

無論是for迴圈還是foreach迴圈,內部都是對該數組的訪問,而迭代器僅僅是多進行了一次版本檢測。事實上,在迴圈內部,兩者產生的IL代碼也是差不多的,但是,正如本建議剛開始提到的那樣,因為版本檢測的緣故,foreach迴圈並不能代替for迴圈。

 

 

轉自:《編寫高品質代碼改善C#程式的157個建議》陸敏技

 

【轉】編寫高品質代碼改善C#程式的157個建議——建議18:foreach不能代替for

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.