AI智能
改变未来

C# IEnumerable Foreach 深入理解


阅前提示

本章内容主要针对 C# 中的IEnumerable及其相关内容做详细的解释。
你真的了解Foreach的本质是什么吗?你对yield关键有多少了解呢?希望这篇文章可以让你更清楚的认识你常常会使用的IEnumerable
适合人群:对C#一定使用基础
阅读方式:浏览

正文

Foreach

这是我们除了for 循环之外可能用到最多的循环语句,它写起来比for循环要舒服而且更易于去理解。
但有时候你会不经意的被它简单的外表所迷惑而造成一些错误(比如在foreach中修改列表的值)。接下来我们会深入了解一下foreach的具体实现,当清楚了解之后我们的使用将会更加得心应手。

CIL下的数组遍历

//C#int[] array = new int[]{1,2,3,4,5};foreach(int item in array){...}//CIL 类似生成如下int[] tempArray;int[] array = new int[]{1,2,3,4,5}tempArray = array;for(int counter = 0;(counter < tempArray.Length);counter++){int item = tempArray[counter];...}

能这样变化是因为数组满足 固定长度索引操作[]

由此也可以看出来,Foreach时不要修改集合

IEnumerable

对于不满足上述所说的条件,就需要实现IEnumerable接口
IEnumerable/IEnumerable< T > 是.NET实现集合的一个关键。集合的本质其实就是一个类,并且最起码实现了**IEnumerable/IEnumerable< T >**所规定的方法。

IEnumerable使类成为集合

Interface IEnumerable{public System.Collections.IEnumerator GetEnumerator ();   //这个里面具体实现了 yield return 机制}Interface IEnumerator{public object Current{get;}public bool MoveNext();public void Reset();}

IEnumerable的foreach

//C#IEnumerable<int> array = new IEnumerable<int>(){1,2,3,4,5};foreach(int item in array){...}//CIL 类似生成如下....IEnumerator ator = array.GetEnumerator()while(ator.MoveNext()){ator = array.GetEnumerator()int item = array.Current;...}

没有IEnumerable的foreach

C#编译器不要求一定要实现IEnumerable/IEnumerable< T >才能用foreach对数据类型进行迭代。实际上,编译器采取了一种**“看起来像”**的名称查找方式,即 只要查找到其含有 GetEnumerator()方法,这个方法返回包含Current属性和MoveNext()方法的一个类型,那就可以用foreach

//建立一个有GetEnumerator的类public class LikeIEnumerable{public IEnumerator GetEnumerator(){yield return 1;yield return 2;yield return 3;}}//然后使用foreach进行测试public void Test(){LikeIEnumerable likeEnumerable = new LikeIEnumerable();foreach (var item in likeEnumerable){Log.I(item); //打印出来}}//输出结果://1//2//3

yield

yield关键字是一种语法糖,实际上还是通过实现IEnumberable、IEnumberable< T >、IEnumberator和IEnumberator< T >接口来满足迭代功能

IL阶段下面这部分内容实际上会被生成一个新的类来实现IEnumberable、IEnumberable< T >、IEnumberator和IEnumberator< T >

//类似如下public class YieldClass : IEnumerator<object>, IEnumerator,IEnumerable<object>,IEnumerable,IDisposable

那上面所述的LikeIEnumerable类这部分内容

{//dosomethingyield return 1;//dosomethingyield return 2;//dosomethingyield return 3;}

实际上可以被看作

public class LikeYield{int state = 0;private object mCurrent;public object Current{get{return mCurrent;}}public bool MoveNext(){switch (state){case 0:state++;//dosomethingmCurrent = 1;return true;case 1:state++;//dosomethingmCurrent = 2;return true;case 2:state++;//dosomethingmCurrent = 3;return true;default:return false;}}}

LikeIEnumerable的迭代部分

foreach (var item in likeEnumerable){Log.I(item);}

等同于

while(likeYield.MoveNext()){var item = likeYield.Current;Log.I(item);}

更细致的IL代码可以看这篇文章

c# yield关键字原理详解

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » C# IEnumerable Foreach 深入理解