博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#的惰性枚举
阅读量:5236 次
发布时间:2019-06-14

本文共 2132 字,大约阅读时间需要 7 分钟。

Ruby 2.0有一个新的特性是惰性枚举器,举了一个例子:可以将下面的代码

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可以看到其实编译器帮我们实现了前面我们自己写的方法。

190018371195299.jpg

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

190018504798879.jpg

废话那么多回到惰性枚举上来,其实我们发现,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个元素的方法了。

你在说什么?

其实我就是打算复习一下迭代器而已...

转载于:https://www.cnblogs.com/johnwii/p/4513440.html

你可能感兴趣的文章
【转】总结前端面试过程中最容易出现的问题
查看>>
Java- 简单了解线程 生产者与消费者问题(三)
查看>>
centos rancher 通过本机 docker images 新增container
查看>>
【原】PNG的使用技巧
查看>>
android studio 使用SVN 锁定文件,防止别人修改(基于Android studio 1.4 )
查看>>
4412 uboot启动分析
查看>>
熟用TableView
查看>>
PHP动态页面 生产静态页 方法二
查看>>
Java大数——a^b + b^a
查看>>
poj 3164 最小树形图(朱刘算法)
查看>>
百度贴吧图片抓取工具
查看>>
服务器内存泄露 , 重启后恢复问题解决方案
查看>>
第二阶段冲刺(2)
查看>>
ajax post 传参
查看>>
2.1命令行和JSON的配置「深入浅出ASP.NET Core系列」
查看>>
android一些细节问题
查看>>
KDESVN中commit时出现containing working copy admin area is missing错误提示
查看>>
利用AOP写2PC框架(二)
查看>>
xp sp3安装IIS
查看>>
【动态规划】skiing
查看>>