C# 常用接口学习 IEnumerableT
我们先去看看公开的.Net4.0的源程序中IEnumerable<T>、IEnumerable、IEnumerator<T>和IEnumerator这四个接口是如何声明的:
需加微信交流群的,请加小编微信号zls20210502,切记备注 加群,小编将会第一时间邀请你进群!目前一群满员,只能进二群了!
public interface IEnumerable<out T> : IEnumerable
{
new IEnumerator<T> GetEnumerator();
}
public interface IEnumerator<out T> : IDisposable, IEnumerator
{
new T Current {
get;
}
}
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
public interface IEnumerator
{
bool MoveNext();
Object Current {
get;
}
void Reset();
}
一、接口IEnumerable实现
1、建一个学生数据结构和一个学生集合类:
//student数据结构
class Student
{
public int id;
public string name;
}
//student 集合
class StudentCollection
{
public List<Student> students = new List<Student>();
public void Add(Student student)
{
students.Add(student);
}
}
公开一个Add()方法以添加数据,我们的集合类建立完毕。下来添加数据:
static void Main(string[] args)
{
StudentCollection sc = new StudentCollection();
sc.Add(new Student { id=0,name="Tony"});
sc.Add(new Student { id=1,name="Micheal"});
sc.Add(new Student { id =2, name = "Amy" });
foreach(var s in sc) {...}
}
}
当我们想用foreach()遍历的时候,编译器会告诉我们StudentCollection不包含GetEnumerator,不能用foreach遍历。虽然StudentCollection里面有能用遍历的List<T>,但我们不想在属性上迭代,我们想在类上迭代,不能 foreach(var s in sc.students){...}
现在只有把我们的StudentCollection类改造成能foreach的。
2、继承接口IEnumerable:
当我们在类后面加上:IEnumerable后,Visual Studio IDE会冒出来一个小黄灯泡,点进去有提示自动填充接口的约定,我们选第一项实现接口(Visaul Studio是全世界最贴心的IDE!),IDE会帮我们把SudentCollection改造成以下的:
class StudentCollection:IEnumerable
{
public List<Student> students = new List<Student>();
public void Add(Student student)
{
students.Add(student);
}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
加了一个返回迭代器的方法GetEnumrator。下来按照IEnumetator接口的约定来实现我们的迭代器StudentCollectionEnumerator,用IDE自动补全代码如下:
//迭代器
class StudentCollectionEnumerator : IEnumerator
{
public object Current
{
get
{
throw new NotImplementedException();
}
}
public bool MoveNext()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
}
我的理解是:Current返回当前元素,MoveNext移动到下一个,Reset回到第一个元素。但根据MSDN上面的说法,Reset 方法提供的 COM 互操作性。它不一定需要实现;相反,实施者只需抛出NotSupportedException。但是,如果您选择执行此操作,则应确保没有调用方依赖于Reset功能。
迭代器工作的原理是:先调用MoveNext()方法,然后读取Current得到元素,直到MoveNext返回false。
我们需要3个字段分别放置 元素的位置、元素、元素集。改变后的程序如下:
//迭代器
class StudentCollectionEnumerator : IEnumerator
{
private int _index;
private List<Student> _collection;
private Student value;
public StudentCollectionEnumerator(List<Student> colletion)
{
_collection = colletion;
_index = -1;
}
object IEnumerator.Current
{
get { return value; }
}
public bool MoveNext()
{
_index++;
if (_index >= _collection.Count) { return false; }
else { value = _collection[_index]; }
return true;
}
public void Reset()
{
_index = -1;
}
}
首先,迭代器初始化,引入元素集 _collection,并把索引 _index设置成-1。设置成-1而不是0是因为迭代器首先调用MoveNext,在MoveNext里面我们先把索引+1指向下一个元素,如果索引_index的值初始为0,则第一个元素是元素集[1],第二个元素了。
其次,我们要把object Current改成 IEnumerator.Current,这个是实现迭代器的关键。返回元素。(好像有装箱的行为)
第三,在MoveNext方法内累加索引,并从元素集中读取元素。然后让索引值超出元素集返回个false值。
最后,在Reset方法内让索引值为-1,不过好像直接抛出错误也成。
迭代器写好了,我们在StudentColletion类里面调用:
class StudentCollection : IEnumerable
{
public List students;
public StudentCollection()
{
students = new List();
}
public void Add(Student student)
{
students.Add(student);
}
public IEnumerator GetEnumerator()
{
return new StudentCollectionEnumerator(students);
}
}
测试运行一下,大功告成!我们实现了可枚举的自己的类。
通过观察,发现迭代器主要就是返回一个元素对象,而StudentColletion里面的students元素集是List的,本身就能枚举,我们能不能利用这个不用专门写迭代器来实现枚举呢?
答案是肯定的,我们这样写:
class StudentCollection:IEnumerable
{
public List<Student> students = new List<Student>();
public void Add(Student student)
{
students.Add(student);
}
public IEnumerator GetEnumerator()
{
foreach(var s in students)
{
yield return s;
}
}
}
这样就能实现枚举了,真简单,充分利用了.Net给出的各种可枚举集合,不用再去写GetEnumerator这种累活了。
二、接口IEnumerable<T>实现
如果我们想写一个通用的可foreach的类,用到泛型:
class MyCollection<T>
{
public List<T> mycollection = new List<T>();
public void Add(T value)
{
mycollection.Add(value);
}
}
其实这个MyCollection类只不过是在List<T>外面封装了一层,要实现IEnumable<T>,继承该泛型接口,Visual Studio 的IDE自动帮我们补全后,如下:
class MyCollection:IEnumerable
{
public List mycollection = new List();
public void Add(T value)
{
mycollection.Add(value);
}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
我们直接用上面第二个简单的写法,改成:
class MyCollection:IEnumerable
{
public List mycollection = new List();
public void Add(T value)
{
mycollection.Add(value);
}
public IEnumerator GetEnumerator()
{
foreach(var s in mycollection)
{
yield return s;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
foreach (var s in mycollection)
{
yield return s;
}
}
}
测试运行:
static void Main(string[] args)
{
MyCollection mc = new MyCollection();
mc.Add(0);
mc.Add(1);
mc.Add(2);
foreach(var s in mc) { Console.WriteLine(s); }
Console.ReadKey();
}
大功告成!
虽然第二种写法比较投机,充分利用了.NET Framework给的各种泛型集合可枚举的特征。不过我们也自己实现了一个GetEnumerator(),了解了枚举器的工作原理。本章学习目的达成。
C# 常用接口学习 IEnumerableT相关推荐
- 7 种 Javascript 常用设计模式学习笔记
7 种 Javascript 常用设计模式学习笔记 由于 JS 或者前端的场景限制,并不是 23 种设计模式都常用. 有的是没有使用场景,有的模式使用场景非常少,所以只是列举 7 个常见的模式 本文的 ...
- 盘点springmvc的常用接口
2019独角兽企业重金招聘Python工程师标准>>> 盘点springmvc的常用接口### springmvc是如今非常流行的web开发框架之一.我个人非常喜欢它约定优于配置的理 ...
- 【LeetCode 总结】Leetcode 题型分类总结、索引与常用接口函数
文章目录 零. Java 常用接口函数 一. 动态规划 二. 链表 三. 哈希表 四. 滑动窗口 五. 字符串 六. DFS.BFS 七. 二分法 八. 二叉树 九. 偏数学.过目不忘 and 原地算 ...
- 6-3-1:STL之vector——vector的快速入门、常用接口
文章目录 一:vector介绍 二:vector的常用接口 (1)构造 (2)迭代器 (3)容量操作 (4)元素访问 (5)增删查改 一:vector介绍 vector是一个可变大小数组的序列容器.和 ...
- 6-2-1:STL之string——string的快速入门、常用接口
文章目录 一:几个问题 二:学习string的常用接口 (1)string类对象的构造 (2)容量操作 (3)访问操作 (4)迭代器 (5)修改操作 (6)非成员函数 一:几个问题 1:为什么学习st ...
- 常用增强学习实验环境 II (ViZDoom, Roboschool, TensorFlow Agents, ELF, Coach等)
原文链接:http://blog.csdn.net/jinzhuojun/article/details/78508203 前段时间Nature上发表的升级版Alpha Go - AlphaGo Ze ...
- 【学习总结】-Apsara Clouder专项技能认证:实现调用API接口学习总结
Apsara Clouder专项技能认证:实现调用API接口-学习总结 API的概念: API的特点: API的分类: 为什么要使用API 阿里云API市场 API请求与认证 Web API协议 HT ...
- 常用增强学习实验环境 I (MuJoCo, OpenAI Gym, rllab, DeepMind Lab, TORCS, PySC2)
常用增强学习实验环境 I (MuJoCo, OpenAI Gym, rllab, DeepMind Lab, TORCS, PySC2) 标签: 强化学习OpenAI GymMuJoCoStarCra ...
- 阿里云Apsara Clouder专项技能认证-实现调用API接口-学习笔记
Apsara Clouder专项技能认证-实现调用API接口-学习笔记 阿里云的一个小认证,闲来无事,考一下 一.API简介 API的概念 API(Application Programming In ...
最新文章
- 关于Flutter初始化流程,我必须告诉你的是...
- Leetcode 162. 寻找峰值 解题思路及C++实现
- Redis Sentinel配置小记
- 从 0 开始手写一个 Spring MVC 框架,向高手进阶
- 我的世界光影mod怎么用_玩转光影!闪光灯、反光板怎么用才高级?
- ECCV18 | 如何正确使用样本扩充改进目标检测性能(附Github地址)
- 判断回文串时忽略既非字母又非数字的字符
- @程序员,让8年京东架构师为你解析云原生监控和日志解决方案!
- 听说你决定当全职自由漏洞猎人了?过来人想跟你聊聊
- 【网络/通信】概念的理解 —— 带宽、吞吐量、净荷
- redis中集群的故障恢复
- Qt QDialog简介
- EBS R12.2 ADOP (R12.2 AD Online Patching) - 3
- 小程序中实现搜索功能
- 浅谈大数据时代之影响力
- axios请求下载excel文件以及文件乱码问题
- 【新手入门必看】git 和 github 介绍
- 性能优化系列(五)网络性能优化
- 语音对讲广播转发模块
- TokenGazer:DeFi领域发展良好,量化模型显示MKR处于市值偏低区间