首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C# 常用接口学习 IEnumerable<T>

C# 常用接口学习 IEnumerable<T>

作者头像
用户9127601
发布2021-11-01 10:17:41
发布2021-11-01 10:17:41
1.2K0
举报
文章被收录于专栏:dotNET编程大全dotNET编程大全

我们先去看看公开的.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(),了解了枚举器的工作原理。本章学习目的达成。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 dotNET编程大全 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档