2021年了,`IEnumerator`、`IEnumerable`还傻傻分不清楚?
IEnumerator
、IEnumerable
这两个接口单词相近、含义相关,傻傻分不清楚。
入行多年,一直没有系统性梳理这对李逵李鬼。
最近本人在怼着why神的《其实吧,LRU也就那么回事》,方案1使用数组实现LUR,手写算法涉及这一对接口,借此机会本次覆盖这一对难缠的冤家。
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
的GetEnumerator
方法的返回值转换为IEnumerator
接口。
从英文词根上讲:
IEnumerator接口代表了枚举器,里面定义了枚举方式;
IEnumerable接口代表该对象具备了可被枚举的性质。
总之,IEnumerable的使用要求类实现IEnumerator。如果您想提供对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属性的get访问器
2021年了,`IEnumerator`、`IEnumerable`还傻傻分不清楚?的更多相关文章
- JS魔法堂:属性、特性,傻傻分不清楚
一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...
- Java:接口和抽象类,傻傻分不清楚?
01. 来看网络上对接口的一番解释: 接口(英文:Interface),在 Java 编程语言中是一个抽象类型,是抽象方法的集合.一个类通过继承接口的方式,从而来继承接口的抽象方法. 兄弟们,你们怎么 ...
- [转帖]十分钟快速理解DPI和PPI,不再傻傻分不清!
十分钟快速理解DPI和PPI,不再傻傻分不清! https://baijiahao.baidu.com/s?id=1605834796518990333&wfr=spider&for= ...
- 【华为敏捷/DevOps实践】7. 敏捷,DevOps,傻傻不分清楚【华为云技术分享】
文:姚冬(华为云DevCloud首席技术布道师,资深DevOps与精益/敏捷专家,金融解决方案技术Leader,中国DevOpsDays社区核心组织者) 前言 敏捷是什么?DevOps是什么?两者有什 ...
- 傻傻分不清之 Cookie、Session、Token、JWT
傻傻分不清之 Cookie.Session.Token.JWT 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证明“你是你自己”(比如:你每天上下班打卡,都需要通过指纹打 ...
- Shell中傻傻分不清楚的TOP3
Shell中傻傻分不清楚的TOP3 发布文章 近来小姐姐又犯憨憨错误,问组内小伙伴export命令不会持久化环境变量吗?反正我是问出口了..然后小伙伴就甩给了我一个<The Linux Comm ...
- URI与URL傻傻分不清楚?
前言 总所周知,缓存是解决Http1.1协议传输性能的问题中最主要的手段. 缓存既可以存在于浏览器上,也可以存在于服务器中. 而影响缓存的Http头部有很多,其中Cache-Control是比较重要的 ...
- 【jvm】08-垃圾回收器那么多傻傻分不清?
[jvm]08-垃圾回收器那么多傻傻分不清? 欢迎关注b站账号/公众号[六边形战士夏宁],一个要把各项指标拉满的男人.该文章已在github目录收录. 屏幕前的大帅比和大漂亮如果有帮助到你的话请顺手点 ...
- JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文带你厘清个中曲直,给你个选择SpringDataJPA的理由!
序言 Spring Data JPA作为Spring Data中对于关系型数据库支持的一种框架技术,属于ORM的一种,通过得当的使用,可以大大简化开发过程中对于数据操作的复杂度. 本文档隶属于< ...
随机推荐
- 谈谈 javascript的 call 和 apply用法
定义: ECMAScript规范为所有函数都包含两个方法(这两个方法非继承而来),call和apply,这两个函数都是在特定的作用域中调用函数,能改变函数的作用域,实际上是改变函数体内 this 的值 ...
- 【题解】AcWing 193. 算乘方的牛
原题链接 题目描述 约翰的奶牛希望能够非常快速地计算一个数字的整数幂P(1 <= P <= 20,000)是多少,这需要你的帮助. 在它们计算得到最终结果的过程中只能保留两个工作变量用于中 ...
- js实现弹幕
弹幕是一个很常见的功能,下面是本人封装的一个小小的实现方案,存在不足之处可以提出来或自由改进. 直接上代码:复制可运行 <!DOCTYPE html> <html> <h ...
- Envoy入门实战部署
一.Envoy介绍 官方文档解释: Envoy是专为大型现SOA(面向服务架构)设置的L7代理和通信总线.该项目源于以下理念:网络对应用程序来说应该是透明的.当网络和应用程序出现问题时,应该很容易确定 ...
- 树莓派RPi.GPIO+Flask构建WebApi实现远程控制
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import RPi.GPIO as GPIO from flask import Flask, requ ...
- html 01-认识Web和Web标准
01-认识Web和Web标准 #Web.网页.浏览器 #Web Web(World Wide Web)即全球广域网,也称为万维网. 我们常说的Web端就是网页端. #网页 网页是构成网站的基本元素.网 ...
- 多任务-python实现-多进程文件拷贝器(2.1.10)
@ 目录 1.需求 2.代码 1.需求 当去拷贝一个文件夹的所有文件时,使用多任务拷贝 假如一个文件使用一个进程处理 10000个文件就额可以使用最大值为10的进程池处理(当然max取值看具体主机性能 ...
- 我用 go-zero 一周实现了一个中台系统,已开源!
作者:Jack 最近发现golang社区里出了一个新星的微服务框架,来自好未来,光看这个名字,就很有奔头,之前,也只是玩过go-micro,其实真正的还没有在项目中运用过,只是觉得 微服务,grpc ...
- C#动态实体集的反序列化(动态JSON反序列化)
一.使用场景 我们在将 JSON 反序列化实体集的时候,如果字段是固定的,那么我们序列化非常简单,对应字段写的实体集就可以了.比如下面这种: { "data":[ { " ...
- C#注册OCX控件
注意 COM组件注册到注册表中的位置,是CLSID还是TypeLib 注册方法 代码执行 //声明注册方法 [DllImport("C:\\Windows\\barcodex.ocx&quo ...