C#的惰性枚举
Ruby 2.0有一个新的特性是惰性枚举器,Soi Mort 的博客举了一个例子:可以将下面的代码
File.open(path) {|fp|
fp.each_line. \
select {|line| # 生成了临时数组
/regexp/ =~ line
}. \
each_with_index.map {|line, no| # 生成了临时数组
sprintf("%d: %s\n", no, line)
}. \
first(10).each {|str| # 生成了临时数组
puts(str)
}
}
转换为
File.open(path) {|fp|
fp.each_line.lazy \
select {|line| # 没有临时数组产生
/regexp/ =~ line
}. \
each_with_index.map {|line, no| # 没有临时数组产生
sprintf("%d: %s\n", no, line)
}. \
first(10).each {|str| # 没有临时数组产生
puts(str)
}
} # 甚至在到达EOF之前都不读取数据
这样来避免产生多余的临时对象。这里谈到了惰性枚举,其实这个概念并不算太新鲜,在.NET引以为傲的Linq中,惰性枚举其实越来越重要。
初学C#的时候其实并不容易搞清楚所谓的IEnumerable和IEnumerator,有个时候就糊弄一下觉得大多数情况很少手工操作迭代器和枚举器,用一个foreach就巧妙的解决并自鸣得意。但是看了《CLR via C#》以及一些关于C#的案例和图书似乎都很少出现foreach,有时候还纳闷特么这些人是蠢的么...当然,后来发现foreach的实现方式导致其本身效率是不高的所以...。
回头看.NET的IEnumerable接口:
public interface IEnumerable
{
//
// Methods
//
[DispId (-4)]
IEnumerator GetEnumerator ();
}
这个接口只需要实现一个GetEnumerator的方法,非常简洁。
IEnumerator接口:
public interface IEnumerator
{
//
// Properties
//
object Current {
get;
}
//
// Methods
//
bool MoveNext ();
void Reset ();
}
于是我们便可以实现一个仅能duang出来一个的“列表”:
class OnlyOne : IEnumerable, IEnumerator
{
public IEnumerator GetEnumerator () => this;
public object Current => "caocaoda";
public bool MoveNext () => false;
public void Reset () {}
}
如果把false改为true那就可以一直艹艹哒啦。
但是这样的话,还是很麻烦,毕竟要我们手工实现,说好的C#简单呢...所以M$引入了一个迭代器,用以实现IEnumerable/IEnumerator。
class OnlyOne : IEnumerable
{
public IEnumerator GetEnumerator()
{
Int32 value = 0;
do {
yield return value++;
} while (false);
}
}
省事太多,通过DILASM可以看到其实编译器帮我们实现了前面我们自己写的方法。

通过IL不难看出,其实MoveNext()是一个Switch...

废话那么多回到惰性枚举上来,其实我们发现,IEnumerable和IEnumerator两个接口的实现其实是惰性的,也就是在需要的时候才会获取数据,而不会产生临时的数据,就像前面Ruby一样,使用迭代器不会产生额外的开销。如果我们把false改成了true,还没有“惰性”那玩意儿可够呛...
为什么说Linq其实很依赖惰性枚举呢...举个例子:
public static IEnumerable Take (Int32 much, IEnumerable s)
{
for (int i = 0; i < much; i++) {
yield return s [i];
}
}
我们就可以实现一个在数据源中抓much个元素的方法了。
你在说什么?##
其实我就是打算复习一下迭代器而已...
C#的惰性枚举的更多相关文章
- C#函数式程序设计之惰性列表工具——迭代器
有效地处理数据时当今程序设计语言和框架的一个任务..NET拥有一个精心构建的集合类系统,它利用迭代器的功能实现对数据的顺序访问. 惰性枚举是一个迭代方法,其核心思想是只在需要的时候才去读取数据.这个思 ...
- swfupload多文件上传[附源码]
swfupload多文件上传[附源码] 文件上传这东西说到底有时候很痛,原来的asp.net服务器控件提供了很简单的上传,但是有回传,还没有进度条提示.这次我们演示利用swfupload多文件上传,项 ...
- 聊一聊C# 8.0中的await foreach
AsyncStreamsInCShaper8.0 很开心今天能与大家一起聊聊C# 8.0中的新特性-Async Streams,一般人通常看到这个词表情是这样. 简单说,其实就是C# 8.0中支持aw ...
- C# 8中的Async Streams
关键要点 异步编程技术提供了一种提高程序响应能力的方法. Async/Await模式在C# 5中首次亮相,但只能返回单个标量值. C# 8添加了异步流(Async Streams),允许异步方法返回多 ...
- C#8.0中的 await foreach
AsyncStreamsInCShaper 8.0 C# 8.0中支持异步返回枚举类型async Task<IEnumerable<T>> sync Streams这个功能已经 ...
- Python 入门基础11 --函数基础4 迭代器、生成器、枚举类型
今日目录: 1.迭代器 2.可迭代对象 3.迭代器对象 4.for循环迭代器 5.生成器 6.枚举对象 一.迭代器: 循环反馈的容器(集合类型) 每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的 ...
- Stream01 定义、迭代、操作、惰性求值、创建流、并行流、收集器、stream运行机制
1 Stream Stream 是 Java 8 提供的一系列对可迭代元素处理的优化方案,使用 Stream 可以大大减少代码量,提高代码的可读性并且使代码更易并行. 2 迭代 2.1 需求 随机创建 ...
- Effective Java - 构造器私有、枚举和单例
目录 饿汉式单例 静态常量 静态代码块 懒汉式单例 尝试加锁 同步代码块 双重检查 静态内部类单例 枚举单例 Singleton 是指仅仅被实例化一次的类.Singleton代表了无状态的对象像是方法 ...
- Swift enum(枚举)使用范例
//: Playground - noun: a place where people can play import UIKit var str = "Hello, playground& ...
随机推荐
- apache+tomcat分布式集群搭建
今天搭建apche+tomcat分布式集群,遇到很多问题,在网上找到的很多都不成功,然后和同事一起研究了一下,最终搭建成功了.做个笔记,以备自己以后参考. 1,下载apache.在下载Apache(2 ...
- struts2 xml中重定向
<result name="success" type="redirect">ManagePartAction</result> 重定向 ...
- Objective c, +load, +initialize 方法
+load() 当类被加载入程序的时候会执行+load方法 +initialize() 当类第一次被使用的时候会执行+initialize方法 这两个方法都只会被执行一次.
- C++ JsonCpp 使用(含源码下载)
C++ JsonCpp 使用(含源码下载) 前言 JSON是一个轻量级的数据定义格式,比起XML易学易用,而扩展功能不比XML差多少,用之进行数据交换是一个很好的选择JSON的全称为:JavaScri ...
- UVM Top Testbench
top testbench在top_tb中包含进所有的文件,将DUT放在top_tb中(例化DUT),连接好各个端口,提供clk时钟和rst_n复位信号.最主要的是要给组件中的虚接口设置接口,一般是给 ...
- C# 关于时间
1.2016/7/8 00:10:10 转换成 2016-07-08T 00:10:10 在用VB动态调用WevService的时候,传入的时间格式为2016/7/8 00:10:10,导致调用出错, ...
- dojo 加载Json数据
1.今天研究了dojo datagrid加载WebService后台传上来的数据.研究来研究去发现他不是很难.用谷歌多调试一下就好了. 2.看很多例子,这个例子能够更好的帮我解决问题:https:// ...
- IE、FF、Safari、OP不同浏览器兼容报告
IE.FF.Safari.OP不同浏览器兼容报告 1 浏览器内核简介 Trident IE浏览器(GreenBrowser绿色浏览器, 遨游浏览器....都是IE) Geckos Fi ...
- iOS9支付完成无法获取回调
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id ...
- 小甲鱼python视频第八讲(课后习题)
1.for循环的使用,注意下面代码的区别 for i in range(0,10,2): print("i love you") for i in range(0,10): pri ...