C# IEnumerable和IEnumerator接口浅析

温故而知新,可以为师矣,有空经常复习一下基础知识是有必要的,并且能加深理解和记忆。

Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大,逐一分析一下。

IEnumerable接口

public interface IEnumerable
{
 IEnumerator GetEnumerator();
}

继承IEnumerable接口的类需实现暴露出来的GetEnumerator()方法,并返回一个IEnumerator接口对象,看来真正做事的是IEnumerator,F12看一下IEnumerator又有什么鬼东西。

IEnumerator接口

public interface IEnumerator
{
 object Current { get; }
 bool MoveNext();
 void Reset();
}

IEnumerator接口有三个东东,一个属性Current,返回当前集合中的元素,方法MoveNext()移动到下一个,遍历不都是向后遍历的嘛,Reset(),字面意思重置,这个容易理解。做个假设:既然IEnumerable接口返回是IEnumerator接口迭代器来实现的,那么仅继承IEnumerator迭代器接口能不能实现一个自定义容器?

定义一个Phone类

public class Phone
{
 public string Name;
 public Phone(string name)
 {
  this.Name = name;
 }
}

定义一个名为MyEnumerator迭代器,并现实它接口IEnumerator

public class MyEnumerator : IEnumerator
{
 Phone[] p;
 int idx = -1;
 public MyEnumerator(Phone[] t)
 {
  p = t;
 }
 public object Current
 {
  get
  {
  if (idx == -1)
   return new IndexOutOfRangeException();
  return p[idx];
  }
 }
 public bool MoveNext()
 {
  idx++;
  return p.Length > idx;
 }
 public void Reset()
 {
  idx = -1;
 }
}
class Program
 {
 static void Main(string[] args)
 {
       show("-----------IEnumerator------------");
  Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
  MyEnumerator enumerator = new MyEnumerator(phones);
  while (enumerator.MoveNext())
  {
  Phone p = enumerator.Current as Phone;
  show(p.Name);
  }
  Console.ReadKey();
 }
 static void show(string i)
 {
  Console.WriteLine(i);
 }
 }

结果显示:

果然不出所料,真正做事情的是IEnumerator接口,即可循环访问自定义的一个容器,不过,初衷是想用Foreach来做循环访问、遍历的。那好,那就只能显示IEnumerable接口来做。稍稍改造一下Phone类:

public class Phone : IEnumerable
 {
 public string Name ;
 public Phone(string name)
 {
  this.Name = name;
 }
 Phone[] p;
 public Phone(Phone[] t)
 {
  p = t;
 }
 public IEnumerator GetEnumerator()
 {
  return new MyEnumerator(p);
 }
 }
static void Main(string[] args)
 {
  show("-----------IEnumerator------------");
  Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
  MyEnumerator enumerator = new MyEnumerator(phones);
  while (enumerator.MoveNext())
  {
  Phone p = enumerator.Current as Phone;
  show(p.Name);
  }
  show("-----------IEnumerable------------");
  Phone phoneList = new Phone(phones);
  foreach (Phone p in phoneList)
  {
  show(p.Name);
  }
  Console.ReadKey();
 }

结果显示:

大功告成,再扩展成通用的容器PhonePackage,继承泛型IEnumerable<T>接口即可。

public class PhonePackage<T> : IEnumerable<T>
 {
 private List<T> dataList = null;
 public void Add(T t)
 {
  if (dataList == null)
  dataList = new List<T>();
  dataList.Add(t);
 }
 public IEnumerator<T> GetEnumerator()
 {
  foreach (T t in dataList)
  {
  yield return t;
  }
 }
 IEnumerator IEnumerable.GetEnumerator()
 {
  foreach (T t in dataList)
  {
  yield return t;
  }
 }
 }
static void Main(string[] args)
 {
  show("-----------IEnumerator------------");
  Phone[] phones = new Phone[] { new Phone("iPhone 7s"), new Phone("iPhone 6s"), new Phone("iPhone 5s") };
  MyEnumerator enumerator = new MyEnumerator(phones);
  while (enumerator.MoveNext())
  {
  Phone p = enumerator.Current as Phone;
  show(p.Name);
  }
  show("-----------IEnumerable------------");
  Phone phoneList = new Phone(phones);
  foreach (Phone p in phoneList)
  {
  show(p.Name);
  }
  show("-----------IEnumerable<T>------------");
  PhonePackage<Phone> phonePackage = new PhonePackage<Phone>();
  phonePackage.Add(new Phone("iPhone 7s"));
  phonePackage.Add(new Phone("iPhone 6s"));
  phonePackage.Add(new Phone("iPhone 5s"));
  foreach (Phone p in phonePackage)
  {
  show(p.Name);
  }
  Console.ReadKey();
 }
 static void show(string i)
 {
  Console.WriteLine(i);
 }

结果显示:

IEnumerator迭代器接口挺啰嗦的,yield是简化了遍历的语法糖而已。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • C#中的IEnumerable简介及简单实现实例

    IEnumerable这个接口在MSDN上是这么说的,它是一个公开枚举数,该枚举数支持在非泛型集合上进行简单的迭代.换句话说,对于所有数组的遍历,都来自IEnumerable,那么我们就可以利用这个特性,来定义一个能够遍历字符串的通用方法. 下面先贴出code. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; us

  • C#中的IEnumerable接口深入研究

    C#和VB.NET中的LINQ提供了一种与SQL查询类似的"对象查询"语言,对于熟悉SQL语言的人来说除了可以提供类似关联.分组查询的功能外,还能获取编译时检查和Intellisense的支持,使用Entity Framework更是能够自动为对象实体的查询生成SQL语句,所以很受大中型信息系统设计者的青睐. IEnumerable这个接口可以说是为了这个特性"量身定制",再加上微软提供的扩展(Extension)方法和Lambda表达式,给开发者带来了无穷的便利.

  • 基于C#中IDisposable与IEnumerable、IEnumerator的应用

    C#中如何合理的释放非托管内存?在本文中我们将讲解使用IDisposable释放托管内存和非托管内存. A.首先需要让类实现IDisposable接口,然后实现IDispose方法. A.a核心Disponse(bool isDisponse) 1.此方法首先判断isReadyDisposed(判断是否第一次调用此核心方法),如果不是第一次调用则不做任何操作. 2.再判断是否是析构函数调用?如果是析构函数调用不释放托管资源,其交由GC进行释放,如果析构函数释放托管资源可能之前GC释放过,就会导致

  • C#中IEnumerable、ICollection、IList、List之间的区别

    首先我看看 IEnumerable: // 摘要: // 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代. // // 类型参数: // T: // 要枚举的对象的类型. [TypeDependency("System.SZArrayHelper")] public interface IEnumerable<out T> : IEnumerable { // 摘要: // 返回一个循环访问集合的枚举器. // // 返回结果: // 可用于循环访问集合的 Syst

  • C#中IEnumerable接口用法实例分析

    本文实例讲述了C#中IEnumerable接口用法.分享给大家供大家参考.具体分析如下: 枚举数可用于读取集合中的数据,但不能用于修改基础集合. 最初,枚举数定位在集合中第一个元素前.Reset 方法还会将枚举数返回到此位置.在此位置上,Current 属性未定义.因此,在读取 Current 的值之前,必须调用 MoveNext 方法将枚举数提前到集合的第一个元素. 在调用 MoveNext 或 Reset 之前,Current 返回同一对象.MoveNext 将 Current 设置为下一个

  • C# IEnumerable和IEnumerator接口浅析

    温故而知新,可以为师矣,有空经常复习一下基础知识是有必要的,并且能加深理解和记忆. Foreach常用于循环访问集合,对实现IEnumerable的接口的容器进行遍历,IEnumerable和IEnumerator接口我有时候也有点迷糊,按官方的解释,IEnumerable是枚举器接口,IEnumerator是迭代器接口,从字面意思来看相差不大,逐一分析一下. IEnumerable接口 public interface IEnumerable { IEnumerator GetEnumerat

  • C#中IEnumerable接口介绍并实现自定义集合

    简介 IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于循环访问集合的IEnumerator对象.对于所有数组的遍历,都来自IEnumerable接口.IEnumerator对象有什么呢?它是一个真正的集合访问器,没有它,就不能使用foreach语句遍历集合或数组,因为只有IEnumerator对象才能访问集合中的项,假如连集合中的项都访问不了,那么进行集合的循环遍历是不可能的事情了. 一.foreach在IEnumerable中案例 p

  • C#中可枚举类型详解

    枚举是迭代一个集合中的数据项的过程. 我们经常使用的大多数集合实际上都已经实现了枚举的接口IEnumerable和IEnumerator接口,这样才能使用foreach迭代,有些是含有某种抽象了枚举细节的接口:ArrayList类型有索引,BitArray有Get方法,哈希表和字典有键和值..........其实他们都已经实现了IEnumerable和IEnumerator接口.所以一切的集合和数组都可以用IEnumerable或者IEnumerable<T>接口来定义. IEnumerabl

  • C#中foreach语句深入研究

    1.概述 本文通过手动实现迭代器来了解foreach语句的本质. 2.使用foreach语句遍历集合 在C#中,使用foreach语句来遍历集合.foreach语句是微软提供的语法糖,使用它可以简化C#内置迭代器的使用复杂性.编译foreach语句,会生成调用GetEnumerator和MoveNext方法以及Current属性的代码,这些方法和属性恰是C#内置迭代器所提供的.下面将通过实例来说明这一切. 例1:使用foreach来遍历集合 //*************************

  • C#入门学习之集合、比较和转换

    目录 一.集合 1.使用集合 2.自定义集合 3.索引符 4.关键字值集合和IDictionary 5.迭代器 6.迭代器和集合 7.深度复制 二.比较 1.类型比较 封箱和拆箱 is运算符 2.值比较 运算符重载 IComparable和IComparer接口 三.转换 1.重载转换运算符 2.as运算符 一.集合 C#中的数组是作为System.Array类的实例来执行的,它们是集合类中的一种. 集合类一般用于处理对象列表,其功能是通过执行System.Collection中的接口实现的.

  • C# IEnumerator枚举器的具体使用

    1.对象只要一个类型实现了IEnumerable接口就能遍历2.IEnumerator是枚举器,一个接口类,实现MoveNext->Current->Reset3.yield关键字是一个迭代器,相当于实现了IEnumerator枚举器4.IEnumerable是可枚举类型,IEnumerator是枚举器 public class IEnumerableShow {         public void Show() {             int[] array = { 1, 2, 3,

  • C#特性-迭代器(上)及一些研究过程中的副产品

    提到迭代器我们不能不想到迭代器模式,那我就以迭代器模式作为开场白. 在我们的应用程序中常常有这样一些数据结构: 它们是一个数据的集合,如果你知道它们内部的实现结构就可以去访问它们,它们各自的内部存储结构互不相同,各种集合有各自的应用场合.说到这里大家可能想出一大堆这样的集合了:List,Hashtable,ArrayList等等.这些集合各自都有各自的个性,这就是它们存在的理由.但如果你想遍历它你必须知道它内部的存储细节,作为一个集合元素,把内部细节暴露出来肯定就不好了,这样客户程序就不够稳定了

随机推荐