c#yield,IEnumerable,IEnumerator

foreach 在编译成IL后,实际代码如下:


即:foreach实际上是先调用可枚举对象的GetEnumerator方法,得到一个Enumerator对象,然后对Enumerator进行while循环的相关操作,然后得到可枚举对象中的每一个值。
可以把可枚举对象中的所有值想像成一个链表,Enumerator是链表的指针,Enumerator.Current是当前指向的元素,Enumerator.MoveNext是指针后移。于是用while循环便可以用类似遍历链表的方式得到对象中的所有值。
一个可枚举对象,本身必需实现IEnumerable接口(其中只有一个GetEnumerator方法)。
在GetEnumerator方法中,可以直接返回一个Enumerator对象用于枚举。
也可以用多个yield return返回所有需要枚举的值,yield 语句在这里会创建一个实现了IEnumerator接口的对象。
要注意的是,如果在方法中用了yield return,就不能用普通的return,且如果用了yield return,那么方法体中的代码不会在调用时运行,只会在枚举开始后(调用Enumerator.MoveNext())才开始运行。且每一次枚举都只会运行到下一个yield return。
class test : IEnumerable
{
public static int j = ;
public static string ss = "begin"; public int i = ;
public IEnumerable<string> a()
{
test.ss += "1111111111@"; //string[] aaaa = { "1", "2", "3" }; //return aaaa.AsEnumerable(); test.j++;
yield return test.j.ToString();
test.ss += "1111111111@";
test.j++;
yield return test.j.ToString();
test.j++;
yield return test.j.ToString(); } public IEnumerator GetEnumerator()
{
test.ss += "222222222222222@"; string[] aaaa = { "", "", "" }; return aaaa.GetEnumerator(); //test.j++;
//yield return test.j.ToString();
//test.j++;
//yield return test.j.ToString();
//test.j++;
//yield return test.j.ToString();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(test.ss);
test t = new test(); Console.WriteLine(test.ss); var tb = t.GetEnumerator(); Console.WriteLine(test.ss);
var a = t.a(); Console.WriteLine(test.ss);
var b = a.GetEnumerator();
//var c = b.Current;
//b.MoveNext();
//Console.WriteLine(c);
//b.MoveNext();
Console.WriteLine(test.ss);
int i = ;
foreach (var s in t)
{
i++;
//test.j = i;
Console.WriteLine(test.j + " " + s);
} Console.WriteLine(test.ss); ReadLine();
}
}
如上面的代码,方法GetEnumerator中用的是普通的return,此时运行到
var tb = t.GetEnumerator(); 输出是:begin222222222222222@ 因为调用了t.GetEnumerator();自然会运行 test.ss += "222222222222222@"; 所以输出是 begin222222222222222@ 但继续往下运行,无论是调用了test.a()还是test.a().GetEnumerator() test.ss的值都没有再改变,也就是没有执行 test.ss += "1111111111@"; 也就是此时方法test.a中的代码一直没得得到执行。 直到foreach开始后,即枚举开始(调用了MoveNext),才开始执行test.a方法体中的代码。 也就是说,包含yield return的方法,已经不是一个普通的方法,用普通的调用方式调用该方法,是不会执行里面的任何代码的,直到调用了Enumerator.MoveNext方法。
且每一次调用Enumerator.MoveNext方法,代码只会执行到下一个yield return,并将该yield return返回的结果做为此次枚举的值。
c#yield,IEnumerable,IEnumerator的更多相关文章
- C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield
IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...
- ICollection IEnumerable/IEnumerator IDictionaryEnumerator yield
Enumerable和IEnumerator接口是.NET中非常重要的接口,二者区别: 1. IEnumerable是个声明式的接口,声明实现该接口的类就是“可迭代的enumerable”,但并没用说 ...
- IEnumerable, IEnumerator接口
IEnumerable接口 // Exposes the enumerator, which supports a simple iteration over a non-generic collec ...
- IEnumerable & IEnumerator
IEnumerable 只有一个方法:IEnumerator GetEnumerator(). INumerable 是集合应该实现的一个接口,这样,就能用 foreach 来遍历这个集合. IEnu ...
- 【Unity|C#】基础篇(20)——枚举器与迭代器(IEnumerable/IEnumerator)
[学习资料] <C#图解教程>(第18章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...
- IEnumerable、IEnumerator与yield的学习
我们知道数组对象可以使用foreach迭代进行遍历,同时我们发现类ArrayList和List也可以使用foreach进行迭代.如果我们自己编写的类也需要使用foreach进行迭代时该怎么办呢? IE ...
- 从yield关键字看IEnumerable和Collection的区别
C#的yield关键字由来以久,如果我没有记错的话,应该是在C# 2.0中被引入的.相信大家此关键字的用法已经了然于胸,很多人也了解yield背后的“延迟赋值”机制.但是即使你知道这个机制,你也很容易 ...
- IEnumerable和IEnumerator 详解 (转)
原文链接:http://blog.csdn.net/byondocean/article/details/6871881 参考链接:http://www.cnblogs.com/hsapphire/a ...
- IEnumerable和IEnumerator 详解
初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下 ...
随机推荐
- jquery mobile (一)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- scp 在不同主机之间数据传输
不同的Linux之间copy文件常用有3种方法,第一种就是ftp,也就是其中一台Linux安装ftp Server,这样可以另外一台使用ftp的client程序来进行文件的copy.第二种方法就是采用 ...
- VMware设置虚拟机,并配置远程连接桌面
现在需要使用VMware虚拟出几个window7的机器,用来跑自动化测试. 在配置虚拟机的时候遇到了几个问题: 问题1:虚拟机无法与外界机器通信.(可ping通过). 问题2:外界机器无法链接虚拟机的 ...
- 《C语言程序设计现代方法》第2章 编程题
7 编写一个程序,要求用户输入一个美金数量,然后显示出如何使用最少的20美元.10美元.5美元和1美元来付款. 提示:将付款金额除以20,确定20美元的数量,然后从付款金额中减去20美元的总金额.对其 ...
- [SDOI2015]权值
问题描述: 有一个长度为n的实数序列,,下标从1开始,其中第k个位置的实数为p · (sin(a · k + b) + cos(c · k + d) + 2),sin和cos采用弧度制,其中p,a,b ...
- 运行.class文件提示找不到或者无法加载主类原因
在Java初学之时,用文本文件写了一个“hello world”的简单程序.在dos环境下使用命令javac -test1.java 进行编译. 编译出名称为test1.class的Java运行文件. ...
- [LeetCode] 74. Search a 2D Matrix 解题思路
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...
- linux下在多个文件夹中查找指定字符串的命令
例如,想要在当前文件夹下的多个.c或者.txt文件中查找“shutdown”字符串, 可以使用“grep shutdown ./*.c”或“grep shutdown ./*.txt”即可 使用fin ...
- html自定义checkbox、radio、select —— select篇
上一篇<html自定义checkbox.radio.select —— checkbox.radio篇>介绍了我们是怎么将 html 自带的 checkbox.radio 改成我们自定义的 ...
- python-面向对象(三)——类的特殊成员
类的特殊成员 1. __doc__ 表示类的描述信息 class Foo: """ 描述类信息,这是用于看片的神奇 """ def ...