星空网 > 软件开发 > ASP.net

编写高质量代码改善C#程序的157个建议——建议18:foreach不能代替for

建议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

关键词:C#

C#
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

暴利!4人小团队年挣2500万,竟是做这种黑心生意……:https://www.kjdsnews.com/a/1444189.html
亚马逊FBA中转的优势和劣势:选择合适的物流方案:https://www.kjdsnews.com/a/1444190.html
美国邮政新规打击虚假面单!一大批跑水账号被曝光:https://www.kjdsnews.com/a/1444191.html
2023年数字广告营销趋势!:https://www.kjdsnews.com/a/1444192.html
用TikTok打入东南亚千亿美妆市场:https://www.kjdsnews.com/a/1444193.html
法国海外仓一件代发操作流程,法国海外仓一件代发是如何收费的?:https://www.kjdsnews.com/a/1444194.html
武陵山大裂谷周围景点 武陵山大裂谷周围景点图片:https://www.vstour.cn/a/411233.html
南美旅游报价(探索南美洲的旅行费用):https://www.vstour.cn/a/411234.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流