【.com原稿】作为开发者,我们经常在程序中写foreach语句来遍历类型,但并不是所有的类型都能遍历,这个知识点是已知的绝大多数给开发成员。然而,程序员并不清楚foreach可以遍历的类型的依据。下面我将通过实例的方式详细讲解foreach的原理。这里我们先自定义一个类型Cat,并遍历这个类型://DefineCattypeclassCat{}//TraverseCatclassProgram{staticvoidMain(string[]args){Catcat=newCat();foreach(varitemincat){//morecode}}}我们运行上面的代码后,编译器会提示“Cat”不包含“GetEnumerator”的公共定义的错误,所以foreach语句不能作用于“Cat”类型的变量。从这个错误提示我们可以知道,如果Cat类型可以foreach遍历,那么Cat类必须实现GetEnumerator方法。接下来,我们将GetEnumerator方法添加到Cat类。classCat{//添加GetEnumerator方法的实现publicobjectGetEnumerator(){returnnull;}}我们再次运行代码,程序显示如下两条错误信息:foreachrequiresthereturntype"object"of"Cat.GetEnumerator()"必须具有适当的公共MoveNext方法和公共Current属性;对象不包含“MoveNext”的定义。根据上面的错误信息,我们可以推断,GetEnumerator方法的返回值一定有MoveNext方法和Current属性。但是我们不知道GetEnumerator方法的返回值类型和Current属性是否是只读的。在这种情况下我们应该怎么办?至此,我们可以看到已经支持foreach遍历的类型是如何完成的。下面的代码段展示了字符串类型是如何实现的(只列出了关键代码)。//morecodepublicCharEnumeratorGetEnumerator();//morecodepublicsealedclassCharEnumerator:ICloneabe,IEnumerator,IEnumerator,IDisposable{publiccharCurrent{get;}//morecodepublicboolMoveNext();//morecode}根据上面的代码段,我们模仿如下:classCat{publicCatEnumeratorGetEnumerator(){returnnewCatEnumerator();}}classCatEnumerator{publiccharCurrent{get;}publicboolMoveNext(){returntrue;}}这时候我们编译,发现原来的错误已经消失,程序编译成功了。但是不要以为到这里就结束了。仅将这些包含在Cat类中没有任何意义。这些内容仅供编译程序之用。在实际开发中,我们遍历的对象是一个序列,所以我们现在要在Cat类中加入一个固定的序列:classCat{string[]datas=newstring[]{"波斯猫","大花猫","无毛猫",“大花猫”};publicCatEnumeratorGetEnumerator(){returnnewCatEnumerator();}}我们已经添加了数据对象,那么foreach是如何访问这个数据的呢?这时候我们可以通过GetEnumerator方法将数据对象作为迭代计数器对象(CatEnumerator)构造函数的参数传入,然后迭代计数器对象提供一个属性来存储这些数据。classCat{string[]datas=newstring[]{"波斯猫","浣熊猫","无毛猫","虎斑猫"};publicCatEnumeratorGetEnumerator(){returnnewCatEnumerator(datas);}}classCatEnumerator{//存储数据privatestring[]datas;//带参数的构造函数publicCatEnumerator(string[]datas){this.datas=datas;}publiccharCurrent{get;}publicboolMoveNext(){returntrue;}}至此我们设置好了要遍历的数据,如果要遍历数据,需要一个下标索引来读取数组中的每一个元素,并将每次读取到的元素的值赋值给Current属性.我们可以在迭代计数器对象中定义一个索引整型私有属性作为下标索引属性。这里需要注意的是,我们的index属性的默认值是-1,这是很多新手开发者容易出错的地方。既然有了下标,那么当我们遍历的时候,下标就必须递增变化,不断指向下一个元素的位置,直到到达数组的末尾。这时候我们需要在MoveNext方法中进行下标自增操作。MoveNext方法是一个返回值为bool类型的方法。它的作用是通知foreach当前遍历的数据对象中是否还有尚未遍历的元素。If存在则返回true,否则返回false,遍历结束。让我们为这段话写代码。classCatEnumerator{//存储数据privatestring[]datas;//带参数的构造函数publicCatEnumerator(string[]datas){this.datas=datas;}//数组下标privateintindex=-1;//遍历当前元素publiccharCurrent{get{returndatas[index];}}publicboolMoveNext(){index++;returnindex>调用MoveNext方法>>获取Current属性。提示:在c#中如果要查看一个类型是否支持foreach,可以查看该类型和该类型的迭代计数器是否实现了IEnumerable接口,因为IEnumerable接口包含了foreach实现的原理和必须调用的成员.作者简介朱刚,笔名苗叔,国内技术博客认证专家,.NET高级开发工程师。7年一线开发经验,参与过电子政务系统和AI客服系统的开发,以及互联网招聘网站的架构设计。目前就职于一家创业公司,从事企业级安全监控系统的开发。【原创稿件,合作网站转载请注明原作者和出处为.com】