IEnumerable接口

IEnumerable接口:实现该接口的类,表明该类下有可以枚举的元素

public interface IEnumerable
{
//返回一个实现了IEnumerator接口的对象
//我的理解:实现该接口的类,用其下哪个可枚举的元素实现该方法那么当该类被枚举时,将得到该类下的某个可枚举元素的元素
IEnumerator GetEnumerator();
}
public class TestEnumerable : IEnumerable
{
//可枚举元素
private Student[] _students; public TestEnumerable(Student[] list)
{
_students = list;
} public IEnumerator GetEnumerator()
{
//当TestEnumerator被枚举时,将得到_students的元素
return _students.GetEnumerator();
}
} public class Student
{
public string ID { get; set; } public string Name { get; set; } public Student(string id, string name)
{
ID = id;
Name = name;
}
}

调用代码:

public static void Main()
{
Student[] students = new Student[]
{
new Student("ID1", "Name1"),
new Student("ID2", "Name2"),
new Student("ID3", "Name3"),
}; TestEnumerable testEnumerable = new TestEnumerable(students); foreach (Student s in testEnumerable)
{
Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name);
}
}

如上文所说, TestEnumerable类用foreach枚举,得到的每一个对象就是上文提到的“可以枚举的元素(Student[])的每一个对象” 。

IEnumerator接口:枚举的真正实现

public interface IEnumerator
{
//获取集合中的当前元素
object Current{get;set;} //枚举数推进到集合的下一个元素,当存在下一个对象时返回true,不存在时返回false
bool MoveNext(); //枚举数设置为其初始位置,该位置位于集合中第一个元素之前
void Reset();
}
public class TestEnumerator : IEnumerator
{
  //指针,指向枚举元素 (为什么这里是-1,因为在MoveNext()中,_position++)
  private int _position = -;
  private Student[] _students;
  public TestEnumerator() { }
  public TestEnumerator(Student[] list)
  {
    _students = list;
  }   /// <summary>
  /// 获取当前元素
  /// </summary>
  public object Current
  {
    get
    {
      return _students[_position];
    }
  }   /// <summary>
  /// 移动到下一个元素
  /// </summary>
  /// <returns>成功移动到下一个元素返回:true;失败返回:false</returns>
  public bool MoveNext()
  {
    _position++;
    return _position < _students.Length;
  }   /// <summary>
  /// 重置到第一个元素
  /// </summary>
  public void Reset()
  {
    _position = -;
  }
} public class TestEnumerable2 : IEnumerable
{
  private Student[] _students;
  public TestEnumerable2(Student[] list)
  {
    _students = list;
  }   public IEnumerator GetEnumerator()
  {
    return new TestEnumerator(_students);
  }
}

调用代码:

public static void Main()
{
Student[] students = new Student[]
{
new Student("ID1", "Name1"),
new Student("ID2", "Name2"),
new Student("ID3", "Name3"),
}; TestEnumerable2 testEnumerator = new TestEnumerable2(students); foreach (Student s in testEnumerator)
{
Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name);
}
}

IEnumerable接口与IEnumerator接口算介绍完毕了。

大家看IEnumerator接口的实现,就是实现一个属性,两个调整枚举点的方法。如果能有一种方式,能自动帮我们完成IEnumerator接口的实现,那么将方便很多。

在.NET Framework 3.5中有了yield,这个关键字可以帮我们自动生成实现IEnumerator的类。

yield

yield关键字,可以帮我们自动生成一个实现了IEnumerator的类,来完成枚举。

下面,我们先来看一下MSDN上的介绍

1.foreach 循环的每次迭代都会调用迭代器方法
2.迭代器方法运行到 yield return 语句时,会返回一个expression表达式并保留当前在代码中的位置
3.当下次调用迭代器函数时执行从该位置重新启动

其实msdn这里解释的有点啰嗦了。简单点说,就是迭代器运行到yield return语句时,将自动做两件事。

1.记录当前访问的位置
2.当下次调用迭代器函数时执行从该位置重新启动:MoveNext()

下面我们来看一段实例代码:

public class TestEnumerable3 : IEnumerable
{
private Student[] _students; public TestEnumerable3(Student[] list)
{
_students = list;
} //实现与之前有不同
public IEnumerator GetEnumerator()
{
//迭代集合
foreach (Student stu in _students)
{
//返回当前元素,剩下的就交给yield了,它会帮我们生成一个实现了接口IEnumerator的类
//来帮我们记住当前访问到哪个元素。
yield return stu;
}
}
}

下面我贴出一段GetEnumerator()方法的IL代码,来证明yield return 帮我们自动生成了一个实现了IEnumerator接口的类

.method public final hidebysig newslot virtual
instance class [mscorlib]System.Collections.IEnumerator GetEnumerator () cil managed
{
// Method begins at RVA 0x228c
// Code size 20 (0x14)
.maxstack
.locals init (
[] class TestBlog.TestEnumerable3/'<GetEnumerator>d__0', //这句最重要,初始化了一个实现System.Collections.IEnumerator的class,存储在索引1的位置
[] class [mscorlib]System.Collections.IEnumerator
) IL_0000: ldc.i4.
IL_0001: newobj instance void TestBlog.TestEnumerable3/'<GetEnumerator>d__0'::.ctor(int32)
IL_0006: stloc.
IL_0007: ldloc.
IL_0008: ldarg.
IL_0009: stfld class TestBlog.TestEnumerable3 TestBlog.TestEnumerable3/'<GetEnumerator>d__0'::'<>4__this'
IL_000e: ldloc.
IL_000f: stloc.
IL_0010: br.s IL_0012 IL_0012: ldloc.
IL_0013: ret
} // end of method TestEnumerable3::GetEnumerator

最后就是调用代码:

static void Main(string[] args)
{
Student[] students = new Student[]
{
new Student("ID1", "Name1"),
new Student("ID2", "Name2"),
new Student("ID3", "Name3"),
}; TestEnumerable3 testEnumerable3 = new TestEnumerable3(students); foreach (Student s in testEnumerable3)
{
Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name);
}
}

IEnumerable构建迭代方法

/// <summary>
/// IEnumerable构建迭代方法
/// <param name="_students">排序集合</param>
/// <param name="direction">排序顺序(true:顺序;false:倒序)</param>
public IEnumerable SortStudents(Student[] _students,bool direction)
{
if (direction)
{
foreach (Student stu in _students)
{
yield return stu;
}
}
else
{
for (int i = _students.Length; i != ; i--)
{
yield return _students[i - ];
}
}
}

细心的朋友一定发现了。这个方法的返回类型为IEnumerable,而不像实现接口IEnumerable的GetEnumerator()方法返回类型是IEnumerator。这就是IEnumerable构建迭代方法需要注意的地方。

下面是测试代码:

static void Main(string[] args)
{
Student[] students = new Student[]
{
new Student("ID1", "Name1"),
new Student("ID2", "Name2"),
new Student("ID3", "Name3"),
};    foreach (Student s in SortStudents(students,false))
{
Console.WriteLine("ID:{0};Name:{1}", s.ID, s.Name);
}
}

感谢大家的耐心阅读。

IEnumerable与IEnumerator的更多相关文章

  1. 细说 C# 中的 IEnumerable和IEnumerator接口

    我们先思考几个问题: 为什么在foreach中不能修改item的值? 要实现foreach需要满足什么条件? 为什么Linq to Object中要返回IEnumerable? 接下来,先开始我们的正 ...

  2. 迭代器学习之一:使用IEnumerable和IEnumerator接口

    写博客是检验我学习的成果之一以及自我总结的一种方式,以后会经常利用这种方式进行技术交流和自我总结,其中认识不深难免会有错误,但是一直懂得不懂就问,不懂就学的道理! 1.首先看一个简单的列子 , , , ...

  3. C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield

    IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...

  4. IEnumerable和IEnumerator

    概述 IEnumerable和IEnumerator接口存在的意义:用来实现迭代的功能! public interface IEnumerable { IEnumerator GetEnumerato ...

  5. 关于迭代器中IEnumerable与IEnumerator的区别

    首先是IEnumerable与IEnumerator的定义: 1.IEnumerable接口允许使用foreach循环,包含GetEnumerator()方法,可以迭代集合中的项. 2.IEnumer ...

  6. IEnumerable和IEnumerator 详解 (转)

    原文链接:http://blog.csdn.net/byondocean/article/details/6871881 参考链接:http://www.cnblogs.com/hsapphire/a ...

  7. C#基础知识系列九(对IEnumerable和IEnumerator接口的糊涂认识)

    前言 IEnumerable.IEnumerator到现在为止对这两个接口还是不太理解,不理解但是自己总是想着试着要搞明白,毕竟自己用的少,所以在此先记录一下.以备自己日后可以来翻查,同时也希望园子里 ...

  8. [转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable

    1.首先看一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Re ...

  9. 转载IEnumerable与IEnumerator区别

    public interface IEnumerable {     IEnumerator GetEnumerator(); }   public interface IEnumerator {   ...

  10. IEnumerable、IEnumerator与yield的学习

    我们知道数组对象可以使用foreach迭代进行遍历,同时我们发现类ArrayList和List也可以使用foreach进行迭代.如果我们自己编写的类也需要使用foreach进行迭代时该怎么办呢? IE ...

随机推荐

  1. visual studio code 的必装推荐插件plugin, vscode, vsc

    An Old Hope Theme     (theme, 推荐,且推荐它的 classic theme,安装后在颜色选项里选择,该插件的定制见文末) Cobalt2     (theme) Drac ...

  2. springmvc接收参数

    springmvc执行流程 搭建ssm框架:http://www.cnblogs.com/liyafei/p/7955413.html 1:从表单中接收 普通请求参数 结构目录 role.html 1 ...

  3. windows下编译和安装boost库

    boost是一个功能强大.构造精巧.跨平台.开源并且完全免费的C++程序库. 获取方式 boost提供源码形式的安装包,可以从boost官方网站下载,目前最新版本是1.59.0. 本机上正好有boos ...

  4. smali过滤特定字符串

    过滤插入代码: const-string/jumbo v0, "aaaaaaa" invoke-static {v0}, Lcom/bihu/insurancerobot/util ...

  5. c++实现web服务框架

    lamada表达式 声明一个返回数组指针的函数            返回指针数组的函数形式如下所示:    括号必须存在 注意->后不能加() Lambda表达式  

  6. .Net Core2.0基于DbContext,IActionFilter过滤器实现全局UOW,不使用TransactionScope

    抛弃TransactionScope 之前实现过类似功能是使用的TransactionScope,总碰到这样那样的问题,新项目迁移到.net core2.0下,果断抛弃之前的写法,因为DbContex ...

  7. zoj3814

    这题说的是给了一个数在longlong范围内 然后求出小于这个数的最大的回文,枚举每位减去1后 , 他后面的位置上全部都置为9,然后在枚举每个前半部分,然后贪心取得这个数的最大值,贪心的时候写错了,错 ...

  8. Linux中编写Bash脚本的10个技巧

    Shell 脚本编程 是你在 Linux 下学习或练习编程的最简单的方式.尤其对 系统管理员要处理着自动化任务,且要开发新的简单的实用程序或工具等(这里只是仅举几例)更是必备技能. 本文中,我们将分享 ...

  9. NetSuite助力各行业企业快速发展

    Oracle NetSuite今天发布了一系列全新技术创新,帮助各行各业企业提升收入.海外扩张以及赋能更多业务用户.最新推出的商务管理.财务管理和分析能力可协助企业利用NetSuite平台来超越客户预 ...

  10. MySQL分区(Partition)功能

    引用地址:http://blog.csdn.net/tjcyjd/article/details/11194489 自5.1开始对分区(Partition)有支持 = 水平分区(根据列属性按行分)=举 ...