zoukankan      html  css  js  c++  java
  • IEnumerable 使用foreach 详解

    我们先思考几个问题:

    1. 为什么在foreach中不能修改item的值?
    2. 要实现foreach需要满足什么条件?
    3. 为什么Linq to Object中要返回IEnumerable?

    接下来,先开始我们的正文。

    自己实现迭代器

    .net中迭代器是通过IEnumerable和IEnumerator接口来实现的,今天我们也来依葫芦画瓢。

    首先来看看这两个接口的定义:

    并没有想象的那么复杂。其中IEnumerable只有一个返回IEnumerator的GetEnumerator方法。而IEnumerator中有两个方法加一个属性。

    接下来开发画瓢,我们继承IEnumerable接口并实现:

    下面使用原始的方式调用:

    有朋友开始说了,我们平时都是通过foreache来取值的,没有这样使用过啊。好吧,我们来使用foreach循环:

    为什么说基本上是等效的呢?我们先看打印结果,在看反编译代码。

    由此可见,两者有这么个关系:

    我们可以回答第一个问题了“为什么在foreach中不能修改item的值?”:

    我们还记得IEnumerator的定义吗

     

    接口的定义就只有get没有set。所以我们在foreach中不能修改item的值。

    我们再来回答第二个问题:“要实现foreach需要满足什么条件?”:

    必须实现IEnumerable接口?NO

    我们自己写的MyIEnumerable删掉后面的IEnumerable接口一样可以foreach(不信?自己去测试)。

    所以要可以foreach只需要对象定义了GetEnumerator无参方法,并且返回值是IEnumerator或其对应的泛型。细看下图:

    也就是说,只要可以满足这三步调用即可。不一定要继承于IEnumerable。有意思吧!下次面试官问你的时候一定要争个死去活来啊,哈哈!

    yield的使用

    你肯定发现了我们自己去实现IEnumerator接口还是有些许麻烦,并且上面的代码肯定是不够健壮。对的,.net给我们提供了更好的方式。

    你会发现我们连MyIEnumerator都没要了,也可以正常运行。太神奇了。yield到底为我们做了什么呢?

    好家伙,我们之前写的那一大坨。你一个yield关键字就搞定了。最妙的是这块代码:

    这就是所谓的状态机吧!

    我们继续来看GetEnumerator的定义和调用:

    我们调用GetEnumerator的时候,看似里面for循环了一次,其实这个时候没有做任何操作。只有调用MoveNext的时候才会对应调用for循环:

    现在我想可以回答你“为什么Linq to Object中要返回IEnumerable?”:

    因为IEnumerable是延迟加载的,每次访问的时候才取值。也就是我们在Lambda里面写的where、select并没有循环遍历(只是在组装条件),只有在ToList或foreache的时候才真正去集合取值了。这样大大提高了性能。

    如:

    这个时候得到了就是IEnumerable对象,但是没有去任何遍历的操作。(对照上面的gif动图看)

    什么,你还是不信?那我们再来做个实验,自己实现MyWhere:

    现在看到了吧。执行到MyWhere的时候什么动作都没有(返回的就是IEnumerable),只有执行到ToList的时候才代码才真正的去遍历筛选。

    这里的MyWhere其实可以用扩展方法来实现,提升逼格。(Linq的那些查询操作符就是以扩展的形式实现的)[了解扩展方法]。

    怎样高性能的随机取IEnumerable中的值

    这段代码来源《深入理解C#》,个人觉得非常妙。贴出来给大家欣赏哈。

    结束:

    demo下载:http://pan.baidu.com/s/1dE94c1b

    接下篇:《再讲IQueryable<T>,揭开表达式树的神秘面纱

  • 相关阅读:
    Spring Boot 使用 Dom4j XStream 操作 Xml
    Spring Boot 使用 JAX-WS 调用 WebService 服务
    Spring Boot 使用 CXF 调用 WebService 服务
    Spring Boot 开发 WebService 服务
    Spring Boot 中使用 HttpClient 进行 POST GET PUT DELETE
    Spring Boot Ftp Client 客户端示例支持断点续传
    Spring Boot 发送邮件
    Spring Boot 定时任务 Quartz 使用教程
    Spring Boot 缓存应用 Memcached 入门教程
    ThreadLocal,Java中特殊的线程绑定机制
  • 原文地址:https://www.cnblogs.com/pangguoming/p/5896822.html
Copyright © 2011-2022 走看看