原文:[原译]实现IEnumerable接口&理解yield关键字

著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

本文讨论题目的内容。然后讨论IEnumerable接口如何使得foreach语句可以使用。之后会展示如果实现自定义的集合类,该集合类实现了IEnumerable接口。Yield关键字和遍历集合后面也讨论。

背景

一使用集合。就发现遍历集合就跟着来了。遍历集合最好的方式是实现迭代器模式-Understanding and Implementing the Iterator Pattern in C# and C++(这篇文章我过几天翻译一下) ,C#提供foreach来以一种优雅的方式遍历

只要集合实现了IEnumerable 接口就可以用foreach来遍历。

使用代码

首先先看一下内置的集合类如何使用foreach来遍历的。ArrayList实现了IEnumerable 接口。我们看一下

// 看一下实现了IEnumerable 接口的集合如何遍历
ArrayList list = new ArrayList(); list.Add("");
list.Add();
list.Add("");
list.Add(''); foreach (object s in list)
{
Console.WriteLine(s);
}

遍历泛型集合类

Arraylist 是一个通用集合类,遍历泛型集合类也可以。因为这些泛型集合类实现了IEnumerable<T>接口,看一下吧。

// 遍历实现了IEnumerable<T>接口的泛型类
List<string> listOfStrings = new List<string>(); listOfStrings.Add("one");
listOfStrings.Add("two");
listOfStrings.Add("three");
listOfStrings.Add("four"); foreach (string s in listOfStrings)
{
Console.WriteLine(s);

发现了吧。我们自定义的集合类或是泛型集合类应该实现IEnumerable和IEnumerable<T>接口。这样就可以遍历了。

理解yield关键字

在写个实现接口的例子之前,先理解一下yield关键字,yield会记录集合位置。当从一个函数返回一个值的时候,yield可以用。

如下的普通的方法。不论调用多少次,都只会返回一个return

static int SimpleReturn()
{
return ;
return ;
return ;
} static void Main(string[] args)
{
// 看看
Console.WriteLine(SimpleReturn());
Console.WriteLine(SimpleReturn());
Console.WriteLine(SimpleReturn());
Console.WriteLine(SimpleReturn());
}

原因就是普通的return语句不保留函数的返回状态。每一次都是新的调用。然后返回第一个值。

但是使用下面的语句替换后就不一样。当函数第二次调用的时候。会从上次返回的地方继续调用

static IEnumerable<int> YieldReturn()
{
yield return ;
yield return ;
yield return ;
}
static void Main(string[] args) {
// 看看yield return的效果
foreach (int i in YieldReturn())
{
Console.WriteLine(i);
}
}

显然返回1,2,3,唯一要注意的就是函数需要返回IEnumerable。,然后通过foreach调用。

在自定义的集合类里实现Ienumerable接口

现在如果我们在我们的自定义集合里定义一个方法。来迭代所有元素。然后通过使用yield返回。我们就可以成功了。

好。我们定义MyArrayList 类,实现IEnumerable 接口,该接口就会强制我们实现GetEnumerator 函数。这里我们就要使用yield了。

class MyArrayList : IEnumerable
{
object[] m_Items = null;
int freeIndex = ; public MyArrayList()
{
// 对了方便我直接用数组了,其实应该用链表
m_Items = new object[];
} public void Add(object item)
{
// 考虑添加元素的时候
m_Items[freeIndex] = item;
freeIndex++;
} // IEnumerable 函数
public IEnumerator GetEnumerator()
{
foreach (object o in m_Items)
{
// 检查是否到了末尾。数组的话。。。没写好
if(o == null)
{
break;
} // 返回当前元素。然后前进一步
yield return o;
}
}
}

之后你就可以用foreach遍历了。

static void Main(string[] args)
{
//看看调用部分
MyArrayList myList = new MyArrayList(); myList.Add("");
myList.Add();
myList.Add("");
myList.Add(''); foreach (object s in myList)
{
Console.WriteLine(s);
}
}

这个类啊。没写好。也不完整。只要是让你理解。。模拟一下而已。

自定义泛型类里实现Ienumerable<T>接口

class MyList<T> : IEnumerable<T>
{
T[] m_Items = null;
int freeIndex = ; public MyList()
{
// 为了方便。使用数组
m_Items = new T[];
} public void Add(T item)
{
//添加元素
m_Items[freeIndex] = item;
freeIndex++;
} #region IEnumerable<T> Members public IEnumerator<T> GetEnumerator()
{
foreach (T t in m_Items)
{
//检查是否到了末尾。数组的话。。。没写好
if (t == null) // 如果T不是一个可空类型。就中断
{
break;
} // 返回当前元素,然后前进一步
yield return t;
}
} #endregion #region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
// 此处调用泛型版本
return this.GetEnumerator();
} #endregion
}

之后就可以使用foreach了。

static void Main(string[] args)
{
// 使用示例
MyList<string> myListOfStrings = new MyList<string>(); myListOfStrings.Add("one");
myListOfStrings.Add("two");
myListOfStrings.Add("three");
myListOfStrings.Add("four"); foreach (string s in myListOfStrings)
{
Console.WriteLine(s);
}
}

 源代码下载

EnumerableDemo.7z

原文地址: A-Beginners-Tutorial-on-Implementing-IEnumerable-I

著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

[原译]实现IEnumerable接口&理解yield关键字的更多相关文章

  1. 转载yield关键字理解

    实现IEnumerable接口及理解yield关键字   [摘要]本文介绍实现IEnumerable接口及理解yield关键字,并讨论IEnumerable接口如何使得foreach语句可以使用. 本 ...

  2. 从yield关键字看IEnumerable和Collection的区别

    C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易 ...

  3. C#中yield关键字理解

    yield关键字之前用得较少,但是在做项目开发的过程中也遇到了,当时有点迷惑,就顺便研究学习了一下,以下是个人理解,不到之处欢迎拍砖!废话就到这,上代码: class Program { static ...

  4. 深入理解python中的yield关键字

    想必大家都看过这样的代码: 上面的这段代码会计算0-9的平方并打印出来. 那么问题来了,这段代码和我们要说的东西有什么区别呢? 这里的关键字,yield,我在前面的文章里已经发过了.那么yield是什 ...

  5. 理解 ES6 语法中 yield 关键字的返回值

    在 ES6 中新增了生成器函数的语法,本文解释了生成器函数内 yield 关键字的返回值. 描述 根据语法规范,yield 关键字用来暂停和继续执行一个生成器函数.当外部调用生成器的 next() 方 ...

  6. 理解 ES6 语法中 yield* 关键字的作用

    在 ES6 中新增了生成器函数的语法,本文解释了与生成器函数有关的 yield* 关键字,及其使用场景. 描述 根据语法规范,yield* 的作用是代理 yield 表达式,将需要函数本身产生(yie ...

  7. C# 基础小知识之yield 关键字 语法糖

    原文地址:http://www.cnblogs.com/santian/p/4389675.html 对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味 ...

  8. yield 关键字

    yield 关键字向编译器指示它所在的方法是迭代器块.编译器生成一个类来实现迭代器块中表示的行为.在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值.这是一个返回值, ...

  9. C# 基础小知识之yield 关键字

    对于yield关键字我们首先看一下msdn的解释: 如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法.运算符或 get 访问器是迭代器. 通过使用 yield 定义迭代器,可在实现自 ...

随机推荐

  1. 【心情】codeforces涨分啦!

    虽然只有10分. 第二次比赛!

  2. js进阶 11-2 jquery属性如何操作

    js进阶 11-2  jquery属性如何操作 一.总结 一句话总结:jquery中的属性用attr方法表示.jquery中都是方法. 1.jquery中的属性的增删改查操作? 只需要两个方法, at ...

  3. 【u032】均衡发展

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 神牛小R在许多方面都有着很强的能力,具体的说,他总共有m种能力,并将这些能力编号为1到m.他的能力是一 ...

  4. 测试与 debug 心得

    测试不等同于调试,各自都有自己的概念集和方法论. Test:examine input/output pairs. 调试:定位,修改. 但如果能做到错误异常的准确定位,调试的一半以上的工作已经完成了. ...

  5. boost_1_34_1在c++builder6编译(把所有dll文件复制到windows系统目录,所以lib文件复制到bcb6\lib目录)

    boost_1_34_1.zip boost 正则表达式 bcb6编译boost_1_34 有个项目要对大量的文本信息进行分析,以前的方法是自己写函数然后进行分析.现在发现一个正则表达式的处理方法,其 ...

  6. BZOJ 3932 - 主席树

    传送门 题目分析 在只打会主席树模板的情况下做了这道题,也算是深有体会. 首先任务可以差分:一个任务是(s, e, p), 则在s处+1, 在e+1处-1,符合前缀.但是我们要查询指定时间的前k任务之 ...

  7. java基本数据类型练习

    package javafirst;//包名 public class JavaFirstDay { //基本数据类型的练习 public static void main(String[] args ...

  8. Starting MySQL.. ERROR! The server quit without updating PID file (/usr/local/mysql/data/vm10-0-0-19

    输入:service mysqld start 报错: Starting MySQL.. ERROR! The server quit without updating PID file (/usr/ ...

  9. Dropout 理论基础与实战细节

    Dropout: A Simple Way to Prevent Neural Networks from Overfitting 对于 dropout 层,在训练时节点保留率(keep probab ...

  10. Vue Router的官方示例改造

    基于Vue Router 2018年8月的官方文档示例,改造一下,通过一个最简单的例子,解决很多初学者的一个困惑. 首先是官方文档示例代码 <!DOCTYPE html> <html ...