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

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

IEnumerator


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


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


  • MoveNext方法:该方法将集合索引加1,并返回一个bool值,指示是否已到达集合的末尾。


  • Reset方法:它将集合索引重置为其初始值-1,这会使枚举数无效。


  • Current方法: 返回position位置的当前对象


IEnumerable


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


public IEnumerator GetEnumerator()
{
    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接口


using System;
using System.Collections;
namespace ConsoleEnum
{
    public class cars : IEnumerable
    {
        private car[] carlist;
        //Create internal array in constructor.
        public cars()
        {
            carlist= new car[6]
            {
                new car("Ford",1992),
                new car("Fiat",1988),
                new car("Buick",1932),
                new car("Ford",1932),
                new car("Dodge",1999),
                new car("Honda",1977)
            };
        }
        //private enumerator class
        private class  MyEnumerator:IEnumerator
        {
            public car[] carlist;
            int position = -1;
            //constructor
            public MyEnumerator(car[] list)
            {
                carlist=list;
            }
            private IEnumerator getEnumerator()
            {
                return (IEnumerator)this;
            }
            //IEnumerator
            public bool MoveNext()
            {
                position++;
                return (position < carlist.Length);
            }
            //IEnumerator
            public void Reset()
            {
                position = -1;
            }
            //IEnumerator
            public object Current
            {
                get
                {
                    try
                    {
                        return carlist[position];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }  //end nested class
      public IEnumerator GetEnumerator()
      {
          return new MyEnumerator(carlist);
      }
    }
}


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


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


  • foreach每次迭代,实际会访问迭代器的Current属性
相关文章
|
开发框架 前端开发 JavaScript
使用JavaScript、jQuery和Bootstrap构建待办事项应用
使用JavaScript、jQuery和Bootstrap构建待办事项应用
227 0
|
关系型数据库 MySQL 开发工具
MySQL双主复制
MySQL双主复制
345 0
|
存储 移动开发 定位技术
HTML5 Geolocation(地理定位)优化到最高精度
HTML5 Geolocation API 可让网页访问用户的地理位置信息。为优化地理定位精度,需考虑设备、浏览器设置、网络状况及编码实现。使用 `enableHighAccuracy` 选项请求高精度,并确保设备开启 GPS,网络良好。结合多种数据源(如 GPS、Wi-Fi)可提高准确性。利用 `watchPosition` 定期更新位置,并妥善处理定位错误。务必遵循用户隐私原则,获取同意并遵守相关法规。这样可有效提升地理定位的精度与用户体验。
|
SQL 机器学习/深度学习 分布式计算
「大数据架构」Spark 3.0发布,重大变化,性能提升18倍
「大数据架构」Spark 3.0发布,重大变化,性能提升18倍
|
机器学习/深度学习 数据挖掘
神经气体网络(NGN)和不断增长的神经气体网络(GNGN)实现(Matlab代码实现)
神经气体网络(NGN)和不断增长的神经气体网络(GNGN)实现(Matlab代码实现)
335 0
神经气体网络(NGN)和不断增长的神经气体网络(GNGN)实现(Matlab代码实现)
|
负载均衡 Kubernetes 算法
如何使用Docker来实现Nginx的负载均衡和反向代理
如何使用Docker来实现Nginx的负载均衡和反向代理
857 1
|
机器学习/深度学习 人工智能 安全
​2020 AI Era 创新大奖发布!AI领军企业 TOP50 与创新先锋 TOP30 榜单揭晓(三)
2020年虽然艰难,但是在科技创新的星辰大海,中国星舰不曾缺席,无论是巨头还是创业公司都在开启科技创新的「新航道」。3月31日,首期AI家论坛——「创新之都 AI赋智」在中关村软件园圆满举办。论坛上,新智元正式发布了「2020 AI Era 创新大奖」领军企业 TOP50 与创新先锋 TOP30榜单。
393 0
​2020 AI Era 创新大奖发布!AI领军企业 TOP50 与创新先锋 TOP30 榜单揭晓(三)
|
消息中间件 设计模式 存储
钉钉 ANR 实战踩坑与经验总结 | 钉钉 ANR 治理最佳实践
钉钉 ANR 实战踩坑与经验总结 | 钉钉 ANR 治理最佳实践
1692 0
钉钉 ANR 实战踩坑与经验总结 | 钉钉 ANR 治理最佳实践
|
SQL 关系型数据库 数据挖掘
PolarDB for PostgreSQL 开源必读手册-最佳场景实践与压测(下)
PolarDB for PostgreSQL 开源必读手册-最佳场景实践与压测
406 0
PolarDB for PostgreSQL 开源必读手册-最佳场景实践与压测(下)
|
SQL 关系型数据库 MySQL
记一次mysql like concat查询优化
记一次mysql like concat查询优化
1534 0