• IEnumerable和IEnumerable<T>接口


    IEnumerable和IEnumerable<T>接口

    IEnumerable和IEnumerable<T>接口在.NET中是非常重要的接口,它允许开发人员定义foreach语句功能的实现并支持非泛型方法的简单的迭代,IEnumerable和IEnumerable<T>接口是.NET Framework中最基本的集合访问器,这两个接口对于LINQ的理解是非常重要的。

    在面向对象的开发过程中,常常需要创建若干对象,并进行对象的操作和查询,在创建对象前,首先需要声明一个类为对象提供描述,示例代码如下所示。

    using System;
    using System.Collections.Generic;
    using System.Linq;       //使用LINQ命名控件
    using System.Text;
    
    namespace IEnumeratorSample
    {
        class Person     //定义一个Person类
        {
            public string Name;    //定义Person的名字
            public string Age;        //定义Person的年龄
    
            public Person(string name, string age)         //为Person初始化(构造函数)
            {
                Name = name;       //配置Name值
                Age = age;    //配置Age值
            }
        }
    }

         上述代码定义了一个Person类并抽象一个Person类的属性,这些属性包括Name和Age。Name和Age属性分别用于描述Person的名字和年龄,用于数据初始化。初始化之后的数据就需要创建一系列Person对象,通过这些对象的相应属性能够进行对象的访问和遍历,示例代码如下所示。

     1 class Program
     2 {
     3    static void Main(string[] args)
     4    {
     5        Person[] per = new Person[2]  //创建并初始化2个Person对象
     6        {
     7          new Person("guojing","21"),        //通过构造函数构造对象
     8          new Person("muqing","21"),        //通过构造函数构造对象
     9        };
    10        foreach (Person p in per)        //遍历对象
    11           Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age);
    12        Console.ReadKey();
    13        }
    14    }
    15 }

         上述代码创建并初始化了2个Person对象,并通过foreach语法进行对象的遍历。但是上述代码是在数组中进行查询的,就是说如果要创建多个对象,则必须创建一个对象的数组,如上述代码中的Per变量,而如果需要直接对对象的集合进行查询,却不能够实现查询功能。例如增加一个构造函数,该构造函数用户构造一组Person对象,示例代码如下所示。

    1 private Person[] per;
    2 public Person(Person[] array)    //重载构造函数,迭代对象
    3 {
    4    per = new Person[array.Length];   //创建对象
    5    for (int i = 0; i < array.Length; i++)      //遍历初始化对象
    6    {
    7       per[i] = array[i];     //数组赋值
    8    }
    9 }

         上述构造函数动态的构造了一组People类的对象,那么应该也能够使用foreach语句进行遍历,示例代码如下所示。

    1 Person personlist = new Person(per);        //创建对象
    2 foreach (Person p in personlist)                //遍历对象
    3 {
    4    Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age);
    5 }

         在上述代码的foreach语句中,直接在Person类的集合中进行查询,系统则会报错“ConsoleApplication1.Person”不包含“GetEnumerator”的公共定义,因此foreach语句不能作用于“ConsoleApplication1.Person”类型的变量,因为Person类并不支持foreach语句进行遍历。为了让相应的类能够支持foreach语句执行遍历操作,则需要实现派生自类IEnumerable并实现IEnumerable接口,示例代码如下所示。

    1 public IEnumerator GetEnumerator()            //实现接口
    2 {
    3     return new GetEnum(_people);
    4 }

         为了让自定义类型能够支持foreach语句,则必须对Person类的构造函数进行编写并实现接口,示例代码如下所示。

     1 class Person:IEnumerable             //派生自IEnumerable,同样定义一个Personl类
     2 {
     3     public string Name;        //创建字段
     4     public string Age;        //创建字段
     5     public Person(string name, string age)      //字段初始化
     6     {
     7        Name = name;        //配置Name值
     8        Age = age;              //配置Age值
     9     }
    10     public IEnumerator GetEnumerator()    //实现接口
    11     {
    12        return new PersonEnum(per);        //返回方法
    13     }
    14 }

         上述代码重构了Person类并实现了接口,接口实现的具体方法如下所示。

     1 class PersonEnum : IEnumerator          //实现foreach语句内部,并派生
     2 {
     3     public Person[] _per;            //实现数组
     4     int position = -1;               //设置“指针”
     5     public PersonEnum(Person[] list)
     6     {
     7         _per = list;         //实现list
     8     }
     9     public bool MoveNext()      //实现向前移动
    10     {
    11         position++;     //位置增加
    12         return (position < _per.Length);   //返回布尔值
    13     }
    14     public void Reset()           //位置重置
    15     {
    16         position = -1;           //重置指针为-1
    17     public object Current              //实现接口方法
    18     {
    19         get
    20         {
    21             try
    22             {
    23                 return _per[position];        //返回对象
    24             }
    25             catch (IndexOutOfRangeException)       //捕获异常
    26             {
    27                 throw new InvalidOperationException();    //抛出异常信息
    28             }
    29         }
    30     }
    31 }

         上述代码实现了foreach语句的功能,当开发Person类初始化后就可以直接使用Personal类对象的集合进行LINQ查询,示例代码如下所示。

     1 static void Main(string[] args)
     2 {
     3      Person[] per = new Person[2]            //同样初始化并定义2个Person对象
     4      {
     5         new Person("guojing","21"),           //构造创建新的对象
     6         new Person("muqing","21"),            //构造创建新的对象
     7      };
     8      Person personlist = new Person(per);          //初始化对象集合
     9      foreach (Person p in personlist)              //使用foreach语句
    10      Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age);
    11      Console.ReadKey();
    12 }

         从上述代码中可以看出,初始化Person对象时初始化的是一个对象的集合,在该对象的集合中可以通过LINQ直接进行对象的操作,这样做即封装了Person对象也能够让编码更加易读。在.NET Framework 3.5中,LINQ支持数组的查询,开发人员不必自己手动创建IEnumerable和IEnumerable<T>接口以支持某个类型的foreach编程方法,但是IEnumerable和IEnumerable<T>是LINQ中非常重要的接口,在LINQ中也大量的使用IEnumerable和IEnumerable<T>进行封装,示例代码如下所示。

    public static IEnumerable<TSource> Where<TSource>
    
    (this IEnumerable<TSource> source,Func<TSource, Boolean> predicate)          //内部实现
    {
          foreach (TSource element in source)                        //内部遍历传递的集合
          {
              if (predicate(element))
                  yield return element;                              //返回集合信息
           }
    }

         上述代码为LINQ内部的封装,从代码中可以看到,在LINQ内部也大量的使用了IEnumerable和IEnumerable<T>接口实现LINQ查询。IEnumerable原本就是.NET Framework中最基本的集合访问器,而LINQ是面向关系(有序N元组集合)的,自然也就是面向IEnumerable<T>的,所以了解IEnumerable和IEnumerable<T>对LINQ的理解是有一定帮助的

    实例:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Collections;
     6 namespace IEnumeratorSample
     7 {
     8  
     9     class Person : IEnumerable
    10     {
    11         public string Name;//定义Person的名字
    12         public string Age;//定义Person的年龄
    13         public Person(string name, string age)//为Person初始化(构造函数)
    14         {
    15             Name = name;//配置Name值
    16             Age = age;
    17  
    18         }
    19         private Person[] per;
    20         public Person(Person[] array)//重载构造函数,迭代对象
    21         {
    22             per = new Person[array.Length];//创建对象
    23             for (int i = 0; i < array.Length; i++)//遍历初始化对象
    24             {
    25                 per[i] = array[i];//数组赋值
    26             }
    27         }
    28         public IEnumerator GetEnumerator()//实现接口
    29         {
    30             return new PersonEnum(per);
    31         }
    32     }
    33     class PersonEnum : IEnumerator//实现foreach语句内部,并派生
    34     {
    35         public Person[] _per;//实现数组
    36         int position = -1;//设置“指针”
    37         public PersonEnum(Person[] list)
    38         {
    39             _per = list;//实现list
    40         }
    41         public bool MoveNext()//实现向前移动
    42         {
    43             position++;//位置增加
    44             return (position < _per.Length);//返回布尔值
    45         }
    46  
    47         public void Reset()//位置重置
    48         {
    49  
    50             position = -1;//重置指针为-1
    51         }
    52         public object Current//实现接口方法
    53         {
    54             get
    55             {
    56                 try
    57                 {
    58                     return _per[position];//返回对象
    59                 }
    60                 catch (IndexOutOfRangeException)//捕获异常
    61                 {
    62                     throw new InvalidOperationException();//抛出异常信息
    63                 }
    64             }
    65         }
    66     }
    67  
    68  
    69     class Program
    70     {
    71  
    72         static void Main(string[] args)
    73         {
    74             Person[] per = new Person[2]
    75             {
    76                 new Person("guojing","21"),
    77                 new Person("muqing","21"),
    78             };
    79             Person personlist = new Person(per);
    80             foreach (Person p in personlist)//遍历对象
    81             {
    82  
    83                 Console.WriteLine("Name is " + p.Name + " and Age is " + p.Age);
    84  
    85             }
    86             Console.ReadKey();
    87         }
    88     }
    89 }
  • 相关阅读:
    112th LeetCode Weekly Contest Validate Stack Sequences
    112th LeetCode Weekly Contest Minimum Increment to Make Array Unique
    C# 有关系统音量的操作
    C# 关于时区的操作
    WordPress 设置GeoIP数据库目录权限时错误解决方案
    AtCoder Beginner Contest 113 C
    AtCoder Beginner Contest 113 B
    AtCoder Beginner Contest 113 A
    将Tomcat注册为Windows服务
    常用的调试方法
  • 原文地址:https://www.cnblogs.com/abc1069/p/4004435.html
Copyright © 2020-2023  润新知