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的本质. 下 ...
随机推荐
- bootstrap easyUI 的选型
最近开始搭建新的项目后台,开始在Bootstrap 和 EasyUI两个框架上选型,个人还是倾向于Bootstrap,毕竟这个响应式效果是个趋势,并且可以自动兼容不同的屏幕分辨率和设备.
- ubuntu14.04 swap not avalible交换分区不能使用
系统最近特别卡,打开"System monitor"中的resource发现"swap not avalibe".原来系统每交换分区. 我的是笔记本电脑,存储空间有限.首先我下载磁盘分区工具Gpart ...
- debmirror镜像站
如何建立一个Debian镜像网站呢?在Debian的官方网站已经有专门的介绍: http://www.debian.org/mirror/ftpmirror 这是基于rsync软件的方法,网页也提供了 ...
- WordPress文件上传与下载问题解决
网上流传了一些修改WordPress文件上传大小限制的做法,大部分是一个版本,而且说得不够准确,特别是对于生手的指导性不强,本文总结了使用Wordpress博客的朋友在文件上传与下载时大小限制,及文件 ...
- Oracle学习.Windows 命令行 启动ORACLE服务与实例
使用数据库前要先打开数据库的实例和监听器! --总结启动命令如下: lsnrctl [start|stop|status] --启动监听器,停止监听器,查看监听器的 ...
- ios7新特性实践
一 iOS 7 新特性:视图控制器切换API 二 iOS 7系列译文:认识 TextKit 三 iOS 7系列译文:iOS7的多任务处理 四 iOS7 最佳实践:一个天气应用案例(上) 五 iOS7 ...
- Introspector(内省)简单演示样例 与 简单应用
简单演示样例: package com.asdfLeftHand.test; import java.beans.BeanDescriptor; import java.beans.BeanInfo; ...
- NVMe 与 AHCI
http://elf8848.iteye.com/blog/1731274 AHCI: NCQ技术,600MB/S,一个队列,每个队列32个指令 NVME:65000个队列,每个队列65000指令,3 ...
- Choosing a Linux Tracer ------Brendan Gregg's Blog
home Choosing a Linux Tracer (2015) 08 Jul 2015 Linux Tracing is Magic! A tracer is an advanced perf ...
- KDB调试内核
http://www.ibm.com/developerworks/cn/linux/l-kdbug/