建议18:foreach不能代替for
来源:互联网 发布:台湾政治知乎 编辑:程序博客网 时间:2024/04/30 22:11
建议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个建议》陆敏技
- 建议18:foreach不能代替for
- 为什么要用foreach来代替for
- foreach 能够做for不能做的事情
- for foreach
- for&foreach
- for foreach
- for in.forEach.for
- foreach循环之不能
- js forEach不能break
- 建议110:用类来代替enum
- 利用FOR LOOP代替DB2 UNF中不能使…
- 从for到foreach
- for 循环,foreach循环
- for 和 foreach区别
- for vs foreach
- .net for foreach
- foreach for的演变
- for 和 foreach区别
- ie 7 float right 换行
- 单例模式简析
- Android 如何正确使用我们的图片资源
- Java语言--读取文件中的内容
- 使用MyEclipse自动生成hibernate的数据库表
- 建议18:foreach不能代替for
- 用redis实现消息队列
- eclipse离线安装velocity插件
- WCF 基础连接已经关闭: 接收时发生错误
- C# mysqlcheck 检查数据库异常+修复数据库
- sap.新总帐的数据结构
- JAVA多线程实现的三种方式
- Linux内存描述之概述--Linux内存管理(一)
- swift代码之路(二)