• 对[foreach]的浅究到发现[yield]


      闲来无事,翻了翻以前的代码,做点总结,菜鸟从这里起航,呵呵。

    一、List的foreach遍历

      先上代码段[1]:

     1  class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             List<string> dayList = new List<string> { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
     6             foreach (var day in dayList)
     7             {
     8                 Console.WriteLine(day);
     9             }
    10             Console.ReadKey();
    11         }
    12     }

      这是我们经常用的,简单明了,这里就不赘述了。

    二、对List的浅究

      接着我就产生了疑问,List具有怎样的特性才使得foreach可以对它进行遍历呢?这个遍历是如何实现的?

      下面就来浅究,再上代码段[2]:

     1     public class DaysList<T> : System.Collections.IEnumerable
     2     {
     3         T[] daysArry;
     4         public DaysList(T[] days)
     5         {
     6             daysArry = days;
     7         }
     8         public System.Collections.IEnumerator GetEnumerator()
     9         {
    10             for (int i = 0; i < daysArry.Length; i++)
    11             {
    12                 yield return daysArry[i];
    13             }
    14         }
    15     }
    16 
    17     class Program
    18     {
    19         static void Main(string[] args)
    20         {
    21             string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
    22             var daysList = new DaysList<string>(days);
    23 
    24             foreach (string day in daysList)
    25             {
    26                 System.Console.WriteLine(day);
    27             }
    28             Console.ReadKey();
    29         }
    30     }

      通过查阅我们发现LIst是通过实现System.Collections.IEnumerable接口来达到可以被遍历的能力,而实现System.Collections.IEnumerable接口必须实现它里面的GetEnumerator()方法,用来返回一个循环访问集合的枚举器,代码段[2]中就有我对GetEnumerator()方法的实现,其中有个关键字[yield]不知大家注意到没。

      我的理解是:与其说是foreach遍历List,不如说是foreach遍历的是List中的GetEnumerator()方法返回的枚举器,注意这个枚举器实现了IEnumerator 接口,(插句话,IEnumerable接口标识某个类具备被遍历的能力,而IEnumerator 接口则使某个类真正具备这个能力!)。而当foreach对List进行循环遍历时,每个循环就是通过[yield]来分隔的。

    三、对foreach的浅究

      通过标题二,我们大概对List进行了了解,但不清楚,下面看看foreach。

      依旧代码段[3]:

     1     //注意:其中类DaysList<T>的实现同代码段[2]一样
     2     //这里只展示foreach的实现。    
     3     class Program
     4     {
     5         static void Main(string[] args)
     6         {
     7             string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
     8             var daysList = new DaysList<string>(days);
     9 
    10             System.Collections.IEnumerator enumertor = daysList.GetEnumerator();
    11             while (enumertor.MoveNext())
    12             {
    13                 System.Console.WriteLine(enumertor.Current);
    14             }
    15             Console.ReadLine();
    16         }
    17      }

      就像上面说的,foreach其实遍历的是List中的GetEnumerator()方法返回的枚举器enumertor,而这个枚举器所实现的接口IEnumerator中定义了只读的Current属性(用来获取枚举器当前的所指的集合中的元素)、MoveNext方法(将枚举器推进到集合中的下一个元素,返回值代表是否到了集合末尾)、Reset方法(使枚举器指到集合第一个元素之前,也就是重置枚举器),明白了这些,我们就可以像代码段[3]中一样通过[while]语法来实现跟foreach一样的功能了,而上文中的[yield]关键字浅显的理解就是用来划分要遍历的集合中的每个元素的。

      最后,本来还想分析分析这个实现了IEnumerator接口的枚举器是怎么生成的,想象一下它的内部实现,应该很有意思!

      就这样吧,下班了,大家共勉!

  • 相关阅读:
    HDU 2955(01背包问题)
    POJ 2250(LCS最长公共子序列)
    POJ 3356(最短编辑距离问题)
    HDU 1069 Monkey and Banana(LIS最长上升子序列)
    POJ
    HDU 2955(0-1背包问题)
    HDU2602 (0-1背包问题)
    hdu1003 Max Sum(经典dp )
    C题
    D题(贪心)
  • 原文地址:https://www.cnblogs.com/such/p/3782512.html
Copyright © 2020-2023  润新知