IEnumerable和IEnumerable<T>接口在.NET中是非常重要的接口,它允许开发人员定义foreach语句功能的实现并支持非泛型方法的简单的迭代,IEnumerable和IEnumerable<T>接口是.NET Framework中最基本的集合访问器,这两个接口对于LINQ的理解是非常重要的。
在面向对象的开发过程中,常常需要创建若干对象,并进行对象的操作和查询,在创建对象前,首先需要声明一个类为对象提供描述,示例代码如下所示。
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对象,通过这些对象的相应属性能够进行对象的访问和遍历,示例代码如下所示。
{
static void Main(
string[] args)
{
Person[] per =
new Person[
2]
// 创建并初始化2个Person对象 {
new Person(
" guojing ",
" 21 "),
// 通过构造函数构造对象 new Person(
" muqing ",
" 21 "),
// 通过构造函数构造对象 };
foreach (Person p
in per)
// 遍历对象 Console.WriteLine(
" Name is " + p.Name +
" and Age is " + p.Age);
Console.ReadKey();
}
}
}
上述代码创建并初始化了2个Person对象,并通过foreach语法进行对象的遍历。但是上述代码是在数组中进行查询的,就是说如果要创建多个对象,则必须创建一个对象的数组,如上述代码中的Per变量,而如果需要直接对对象的集合进行查询,却不能够实现查询功能。例如增加一个构造函数,该构造函数用户构造一组Person对象,示例代码如下所示。
public Person(Person[] array)
// 重载构造函数,迭代对象 {
per =
new Person[array.Length];
// 创建对象 for (
int i =
0; i < array.Length; i++)
// 遍历初始化对象 {
per[i] = array[i];
// 数组赋值 }
}
上述构造函数动态的构造了一组People类的对象,那么应该也能够使用foreach语句进行遍历,示例代码如下所示。
Person personlist = new Person(per); // 创建对象 foreach (Person p
in personlist)
// 遍历对象 {
Console.WriteLine(
" Name is " + p.Name +
" and Age is " + p.Age);
}
在上述代码的foreach语句中,直接在Person类的集合中进行查询,系统则会报错“ConsoleApplication1.Person”不包含“GetEnumerator”的公共定义,因此foreach语句不能作用于“ConsoleApplication1.Person”类型的变量,因为Person类并不支持foreach语句进行遍历。为了让相应的类能够支持foreach语句执行遍历操作,则需要实现派生自类IEnumerable并实现IEnumerable接口,示例代码如下所示。
public IEnumerator GetEnumerator() // 实现接口 {
return new GetEnum(_people);
}
为了让自定义类型能够支持foreach语句,则必须对Person类的构造函数进行编写并实现接口,示例代码如下所示。
class Person:IEnumerable // 派生自IEnumerable,同样定义一个Personl类 {
public string Name;
// 创建字段 public string Age;
// 创建字段 public Person(
string name,
string age)
// 字段初始化 {
Name = name;
// 配置Name值 Age = age;
// 配置Age值 }
public IEnumerator GetEnumerator()
// 实现接口 {
return new PersonEnum(per);
// 返回方法 }
}
上述代码重构了Person类并实现了接口,接口实现的具体方法如下所示。
class PersonEnum : IEnumerator // 实现foreach语句内部,并派生 {
public Person[] _per;
// 实现数组 int position = -
1;
// 设置“指针” public PersonEnum(Person[] list)
{
_per = list;
// 实现list }
public bool MoveNext()
// 实现向前移动 {
position++;
// 位置增加 return (position < _per.Length);
// 返回布尔值 }
public void Reset()
// 位置重置 {
position = -
1;
// 重置指针为-1 public object Current
// 实现接口方法 {
get {
try {
return _per[position];
// 返回对象 }
catch (IndexOutOfRangeException)
// 捕获异常 {
throw new InvalidOperationException();
// 抛出异常信息 }
}
}
}
上述代码实现了foreach语句的功能,当开发Person类初始化后就可以直接使用Personal类对象的集合进行LINQ查询,示例代码如下所示。
static void Main( string [] args) {
Person[] per =
new Person[
2]
// 同样初始化并定义2个Person对象 {
new Person(
" guojing ",
" 21 "),
// 构造创建新的对象 new Person(
" muqing ",
" 21 "),
// 构造创建新的对象 };
Person personlist =
new Person(per);
// 初始化对象集合 foreach (Person p
in personlist)
// 使用foreach语句 Console.WriteLine(
" Name is " + p.Name +
" and Age is " + p.Age);
Console.ReadKey();
}
从上述代码中可以看出,初始化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的理解是有一定帮助的