• IEnumerable、IEnumerator与yield的学习


    我们知道数组对象可以使用foreach迭代进行遍历,同时我们发现类ArrayList和List也可以使用foreach进行迭代。如果我们自己编写的类也需要使用foreach进行迭代时该怎么办呢?

    IEnumerable:

    1 public interface IEnumerable
    2 {
    3     IEnumerator GetEnumerator();
    4 }

    如果自己编写的类需要foreach进行迭代就需要实现IEnumerable接口,表示当前的类可以进行迭代。

    我们发现该接口唯一的方法返回的是另一个接口IEnumerator,下面看看这个接口是干嘛的。

    IEnumerator:

    1 public interface IEnumerator
    2 {
    3     object Current { get; }
    4     bool MoveNext();
    5     void Reset();
    6 }

    如果说IEnumerable接口是表示当前类可以进行迭代,那么IEnumerator则是实现迭代逻辑的接口,我们需要编写一个实现IEnumerator接口的类并在其中编写好迭代逻辑。

    下面直接上一个例子:

    People.cs:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     /// <summary>
    10     /// 自定义的可迭代类.
    11     /// </summary>
    12     class People : IEnumerable<Person>
    13     {
    14         //这里用了一个 List 有点无聊, 因为 List 本身就可以进行迭代, 为了写例子没办法
    15         private List<Person> _list;
    16 
    17         public People()
    18         {
    19             _list = new List<Person>();
    20         }
    21 
    22         public IEnumerator<Person> GetEnumerator()
    23         {
    24             return new PeopleEnumerator(_list.ToArray());
    25         }
    26 
    27         //示例程序所以这里就添加一个方法就行了
    28         public void AddPerson(Person person)
    29         {
    30             _list.Add(person);
    31         }
    32 
    33         System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    34         {
    35             return this.GetEnumerator();
    36         }
    37     }
    38 
    39     /// <summary>
    40     /// 迭代器的逻辑实现类.
    41     /// </summary>
    42     class PeopleEnumerator : IEnumerator<Person>
    43     {
    44         public Person[] pers;
    45 
    46         private int index = -1;
    47 
    48         public PeopleEnumerator(Person[] pers)
    49         {
    50             this.pers = pers;
    51         }
    52 
    53         public Person Current
    54         {
    55             get
    56             {
    57                 return pers[index];
    58             }
    59         }
    60 
    61         public bool MoveNext()
    62         {
    63             index++;
    64             return index < pers.Length;
    65         }
    66 
    67         public void Reset()
    68         {
    69             index = -1;
    70         }
    71 
    72         public void Dispose()
    73         {
    74             pers = null;
    75         }
    76 
    77         object System.Collections.IEnumerator.Current
    78         {
    79             get { return Current; }
    80         }
    81     }
    82 
    83     /// <summary>
    84     /// 集合的元素.
    85     /// </summary>
    86     class Person
    87     {
    88         public string name;
    89         public bool isMale;
    90 
    91         public Person(string name, bool isMale)
    92         {
    93             this.name = name;
    94             this.isMale = isMale;
    95         }
    96     }
    97 }

    Program.cs:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Test
     8 {
     9     class Program
    10     {
    11         static void Main(string[] args)
    12         {
    13             new Program();
    14 
    15             Console.ReadKey();
    16         }
    17 
    18         public Program()
    19         {
    20             People people = new People();
    21             people.AddPerson(new Person("tony", true));
    22             people.AddPerson(new Person("tony mom", false));
    23             people.AddPerson(new Person("alen", true));
    24             people.AddPerson(new Person("gilbret", true));
    25             people.AddPerson(new Person("mark", false));
    26 
    27             foreach(Person person in people)
    28             {
    29                 Console.WriteLine("Name: {0}, sex is male:{1}", person.name, person.isMale);
    30             }
    31         }
    32     }
    33 }

    下面是运行结果:

    1 Name: tony, sex is male:True
    2 Name: tony mom, sex is male:False
    3 Name: alen, sex is male:True
    4 Name: gilbret, sex is male:True
    5 Name: mark, sex is male:False

    yield:

    yield 是 C# 提供的一个特殊的用于迭代的语法,其可以简化迭代实现的代码,yield return 语句返回集合的一个元素,并移动到下一个元素上,yield break 可以停止迭代。

    头晕了吧?没关系,我们先看看一个简单的例子:

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 
     8 namespace Test
     9 {
    10     class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             new Program();
    15 
    16             Console.ReadKey();
    17         }
    18 
    19         public Program()
    20         {
    21             People people = new People();
    22 
    23             foreach(string name in people)
    24             {
    25                 Console.WriteLine(name);
    26             }
    27         }
    28     }
    29 
    30     class People : IEnumerable
    31     {
    32         public IEnumerator GetEnumerator()
    33         {
    34             yield return "gilbert";
    35             yield return "alen";
    36             yield return "grace";
    37         }
    38     }
    39 }

    运行的结果为:

    1 gilbert
    2 alen
    3 grace

    没错,当程序碰到yield return这个语句时就将其后面附带的数据作为current返回,同时程序会再此处暂停,运行结束foreach中的代码后再继续,同时执行的是下一个语句了,我们再看看yield break的效果,该效果表示立即停止迭代,示例如下:

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 
     8 namespace Test
     9 {
    10     class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             new Program();
    15 
    16             Console.ReadKey();
    17         }
    18 
    19         public Program()
    20         {
    21             People people = new People();
    22 
    23             foreach(string name in people)
    24             {
    25                 Console.WriteLine(name);
    26             }
    27         }
    28     }
    29 
    30     class People : IEnumerable
    31     {
    32         public IEnumerator GetEnumerator()
    33         {
    34             yield return "gilbert";
    35             yield return "alen";
    36             yield break;//指示这里要停止迭代
    37             yield return "grace";
    38         }
    39     }
    40 }

    运行的结果为:

    1 gilbert
    2 alen

    最后要说一下:包含yoeld语句的方法或者属性也称为迭代块,迭代块必须声明为返回IEnumerator或IEnumerable接口,迭代块可以包含多个yield return或yield break语句,但是不能包含return语句。

    不要小看yield迭代快,下一篇笔记我要可转回U3D了,我们要详细的看看yield在U3D里的变种——协程

  • 相关阅读:
    禅道 之 项目开发必备
    Cmd 命令大全
    Php 性能参数优化 及 Iptables 防火墙限制用户访问平率
    Nginx 性能参数优化
    Mysql 性能调优参数
    Postfix的工作原理
    python三次输入错误验证登录
    python shopping incomplete code
    MySQL + Atlas --- 部署读写分离
    网站流量分析项目day03
  • 原文地址:https://www.cnblogs.com/hammerc/p/4428191.html
Copyright © 2020-2023  润新知