|
|
|
|
公众号矩阵

2021年了,`IEnumerator`、`IEnumerable`接口还傻傻分不清楚?

IEnumerator、IEnumerable这两个接口单词相近、含义相关,傻傻分不清楚。入行多年,一直没有系统性梳理这对李逵李鬼。

作者:小码甲来源:全栈码农画像|2021-01-13 08:10

本文转载自微信公众号「全栈码农画像」,作者小码甲  。转载本文请联系全栈码农画像公众号。

IEnumerator、IEnumerable这两个接口单词相近、含义相关,傻傻分不清楚。

入行多年,一直没有系统性梳理这对李逵李鬼。

最近本人在怼着why神的《其实吧,LRU也就那么回事》,方案1使用数组实现LRU,手写算法涉及这一对接口,借此时机覆盖这一对难缠的冤家。

IEnumerator

IEnumerator、IEnumerable接口有相似的名称,这两个接口通常也在一起使用,它们有不同的用途。

IEnumerator接口为类内部的集合提供了迭代方式, IEnumerator 要求你实现三个方法:

  1. MoveNext方法:该方法将集合索引加1,并返回一个bool值,指示是否已到达集合的末尾。
  2. Reset方法:它将集合索引重置为其初始值-1,这会使枚举数无效。
  3. Current方法: 返回position位置的当前对象

IEnumerable

IEnumerable接口为foreach迭代提供了支持,IEnumerable要求你实现GetEnumerator方法。

  1. public IEnumerator GetEnumerator() 
  2.     return (IEnumerator)this; 

该用哪一个接口?

仅凭以上辞藻,很难区分两个接口的使用场景。

IEnumerator接口定义对类中的集合类型对象的迭代方式,

IEnumerable接口允许使用foreach循环进行枚举。

因此IEnumerable接口的GetEnumerator方法会返回一个IEnumerator接口。要实现IEnumerable,你还必须实现IEnumerator。

从英文词根上讲:

IEnumerator接口代表了枚举器,里面定义了枚举方式,是名词。

IEnumerable接口代表该对象具备了可被枚举的性质,是形容词。

总之,如果您想提供对foreach的支持,那么就先让对象可枚举,再谈论枚举方式,也就是说实现这两个接口。

最佳实践

  • 在嵌套类中实现IEnumerator,这样你可以创建多个枚举器。
  • 为IEnumerator的Current方法提供异常处理。

为什么要这么做?

如果集合的内容发生变化,则reset方法将被调用,紧接着当前枚举数无效,您将收到一个IndexOutOfRangeException异常(其他情况也可能导致此异常)。所以执行一个Try…Catch块来捕获这个异常并引发InvalidOperationException异常, 提示在迭代时不允许修改集合内容。

“这也正是我们常见的在foreach 里面尝试修改迭代对象会报InvalidOperationException异常的原因。

下面以汽车列表为例实现IEnumerator IEnumerable接口

  1. using System; 
  2. using System.Collections; 
  3. namespace ConsoleEnum 
  4.     public class cars : IEnumerable 
  5.     { 
  6.         private car[] carlist; 
  7.    
  8.         //Create internal array in constructor. 
  9.         public cars() 
  10.         { 
  11.             carlist= new car[6] 
  12.             { 
  13.                 new car("Ford",1992), 
  14.                 new car("Fiat",1988), 
  15.                 new car("Buick",1932), 
  16.                 new car("Ford",1932), 
  17.                 new car("Dodge",1999), 
  18.                 new car("Honda",1977) 
  19.             }; 
  20.         } 
  21.         //private enumerator class 
  22.         private class  MyEnumerator:IEnumerator 
  23.         { 
  24.             public car[] carlist; 
  25.             int position = -1; 
  26.  
  27.             //constructor 
  28.             public MyEnumerator(car[] list) 
  29.             { 
  30.                 carlist=list; 
  31.             } 
  32.             private IEnumerator getEnumerator() 
  33.             { 
  34.                 return (IEnumerator)this; 
  35.             } 
  36.             //IEnumerator 
  37.             public bool MoveNext() 
  38.             { 
  39.                 position++; 
  40.                 return (position < carlist.Length); 
  41.             } 
  42.             //IEnumerator 
  43.             public void Reset() 
  44.             { 
  45.                 position = -1; 
  46.             } 
  47.             //IEnumerator 
  48.             public object Current 
  49.             { 
  50.                 get 
  51.                 { 
  52.                     try 
  53.                     { 
  54.                         return carlist[position]; 
  55.                     } 
  56.                     catch (IndexOutOfRangeException) 
  57.                     { 
  58.                         throw new InvalidOperationException(); 
  59.                     } 
  60.                 } 
  61.             } 
  62.         }  //end nested class 
  63.       public IEnumerator GetEnumerator() 
  64.       { 
  65.           return new MyEnumerator(carlist); 
  66.       } 
  67.     } 

在foreach cars的时候,可以明显看到

  • foreach语法糖初次接触可枚举的cars, 实际会访问cars实现的 GetEnumerator()方法,拿到迭代器
  • foreach每次迭代,实际会访问迭代器的Current属性

【编辑推荐】

  1. 美团面试:为什么就能直接调用userMapper接口的方法?
  2. Jmeter接口性能及自动化测试实战
  3. Node.js 小知识 — 实现图片上传写入磁盘的接口
  4. 首个双手控制脑机接口:开颅手术10小时植入6个电极,瘫痪人士用意念吃蛋糕
  5. Tep0.6.0更新聊聊Pytest变量接口用例3个级别复用
【责任编辑:武晓燕 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+更多

数据湖与数据仓库的分析实践攻略

数据湖与数据仓库的分析实践攻略

助力现代化数据管理:数据湖与数据仓库的分析实践攻略
共3章 | 创世达人

1人订阅学习

云原生架构实践

云原生架构实践

新技术引领移动互联网进入急速赛道
共3章 | KaliArch

30人订阅学习

数据中心和VPDN网络建设案例

数据中心和VPDN网络建设案例

漫画+案例
共20章 | 捷哥CCIE

209人订阅学习

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO官微