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 }
时间: 2024-11-01 20:02:18

IEnumerable和IEnumerable<T>接口的相关文章

19.C#逐一介绍IEnumerable和IEnumerable&lt;T&gt;中的扩展方法(10.3-10.5)

今天没有太多的言语,只有代码,扩展方法多得太多,不能一一列完,书中一些,看多了也就会使用了. 1 //Enumerable.Range 返回起始到结束范围,是一个Enumrable<int>类型 2 //Range方法并不会真的构造含有适当数字的列表,它只是在恰当的时间生成那些数,"just in time" 3 var c0 = Enumerable.Range(1, 10); 4 foreach (var e in c0) 5 { 6 Console.WriteLine

迭代器学习之一:使用IEnumerable和IEnumerator接口

写博客是检验我学习的成果之一以及自我总结的一种方式,以后会经常利用这种方式进行技术交流和自我总结,其中认识不深难免会有错误,但是一直懂得不懂就问,不懂就学的道理! 1.首先看一个简单的列子 1 int[] myArray = { 1, 32, 43, 343 }; 2 //很少这样写的 3 IEnumerator myie = myArray.GetEnumerator(); //获取需要遍历的枚举数 4 myie.Reset(); //重置 5 while (myie.MoveNext())

foreach为什么要实现IEnumerable接口而不是直接用IEnumerator接口

在.Net中,要想被foreach遍历,那么目标对象要实现IEnumerable或IEnumerable<T>接口,这个接口有一个方法,GetEnumerator(),返回一个IEnumerator接口,这个接口里定义了Next()等方法,例如: public class Garge : IEnumerable { public IEnumerator GetEnumerator { return new A(); } internal class A : IEnumerator { //实现

C#接口之IEnumerable,IEnumerator

IEnumerable 截图来源于https://msdn.microsoft.com/zh-cn/library/system.collections.ienumerable.getenumerator.aspx IEnumerable只包含一个抽象方法GetEnumerable(),它返回一个可用于循环访问集合的IEnumberator对象.我们可以通过定义foreach语句功能实现并支持非泛型方法的迭代. 在MSDN上给出了一个关于GetEnumerable()方法的例子: 1 using

IEnumerable,ICollection,IList接口问题

最近有一个疑问:IList已经继承了ICollection<T>,而ICollection<T>继承了 IEnumerable<T>, IEnumerable,那为什么IList还要继承 IEnumerable<T>, IEnumerable? 于是我自己写了接口测试:用dnSpy反编译看到,Test3接口继承了Test1,Test2.这就说明接口其实不支持跟类一样的继承的,但是我们实际用的时候却跟类用法一样,好像支持继承,这其实是编译器帮我们补齐了接口的定

.NET教程:.NET 面试题之IEnumerable

.NET教程,今天给大家介绍的是:.NET 面试题之IEnumerable ,这是在面试的时候可能会碰到的一道题目,这道题的注解分为了两个部分,这一篇是第一部分! 什么是IEnumerable? IEnumerable及IEnumerable的泛型版本IEnumerable是一个接口,它只含有一个方法GetEnumerator.Enumerable这个静态类型含有很多扩展方法,其扩展的目标是IEnumerable. 实现了这个接口的类可以使用Foreach关键字进行迭代(迭代的意思是对于一个集合

IEnumerable和IQueryable和Linq的查询

IEnumerable和IEnumerable 1.IEnumerable查询必须在本地执行.并且执行查询前我们必须把所有的数据加载到本地.而且更多的时候.加载的数据有大量的数据是我们不需要的无效数据.但是我们却不得不传输更多的数据.做更多的无用功.使用IEnumerable,所有对于IEnumerable的过滤,排序等操作,都是在内存中发生的.也就是说数据已经从数据库中获取到了内存中,只是在内存中进行过滤和排序操作. 2.IQueryable却总能只提供你所需要的数据.大大减少了数据的传输IQ

IEnumerable和IQueryable区别、优缺点

转自 http://www.cnblogs.com/fly_dragon/archive/2011/02/21/1959933.html IEnumerable接口 公开枚举器,该枚举器支持在指定类型的集合上进行简单迭代.也就是说:实现了此接口的object,就可以直接使用foreach遍历此object: IQueryable 接口 它继承 IEnumerable 接口,而因为.net版本加入Linq和IQueryable后,使得IEnumerable不再那么单调,变得更加强大和丰富. 为了区

C#中IEnumerable、ICollection、IList、IQueryable 、IQueryable 之间的区别

一:一个简单的例子 int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Reset(); while (myie.MoveNext()) { int i = (int)myie.Current; Console.WriteLine("Value: {0}", i); } 通常我们这样会这样做: foreach (int item in myArray) Console.