一、什么叫枚举数
enum Day(表示一个枚举)
{
Sun,(表示一个枚举数),隐含的Sun的值为0,0表示枚举数的值
Mon,
Tue,
Wed,
Thu,
Fri,
Sat
};
枚举数是循环访问与之关联集合的对象,枚举数可被理解为指向集合中任何元素的可移动的指针。一个枚举数只能与一个集合管理,但一个集合可以具有多个枚举数。foreach语句使用枚举数来访问集合内元素,并且隐藏了枚举数中的复杂性。
二、什么叫迭代器
为了提供一个能从集合外部访问集合内部元素,而又不需要集合内部细节的功能,C#提供了foreach迭代功能,而配合foreach迭代功能的代码段,叫做迭代器。
迭代器的核心就是定义集合或者数组的枚举数,并公布之,让foreach能够访问。
·.迭代器是可以返回相同类型值的有序序列的一段代码(可以是循环语句,也可以不是);
·迭代器可用作方法、运算符或get访问器的代码体;
·迭代器代码使用yield return语句依次返回每个元素,yield break将终止迭代;
·可以在类中实现多个迭代器,每个迭代器都必须像任何类成员一样有惟一的名称,并且可以在foreach语句中被客户端代码调用;
·迭代器的返回类型必须为IEnumerable、IEnumerator、IEnumerable (T) 或 IEnumerator (T)中的任意一种;
·迭代器是产生值的有序序列的一个语句块,不同于有一个 或多个yield语句存在的常规语句块;
·迭代器不是一种成员,它只是实现函数成员的方式,理解这一点是很重要的,一个通过迭代器实现的成员,可以被其他可能或不可能通过迭代器实现的成员覆盖和重载;
·迭代器块在C#语法中不是独特的元素,它们在几个方面受到限制,并且主要作用在函数成员声明的语义上,它们在语法上只是语句块而已
三、IEnumerable、IEnumerator、IEnumerable (T) 、 IEnumerator (T)
//公布非泛型枚举数
public interface IEnumerable
{
//IEnumerable只有一个方法,返回可循环访问集合的枚举数。
IEnumerator GetEnumerator() ;
}
//公布泛型枚举数
public interface Ienumerable(T)
//定义非泛型枚举数
public interface IEnumerator
{
// 方法
//移到集合的下一个元素。如果成功则返回为 true;如果超过集合结尾,则返回false。
bool MoveNext();
// 将集合设置为初始位置,该位置位于集合中第一个元素之前
void Reset();
// 属性:获取集合中的当前元素
object Current { get; }
}
//定义泛型枚举数
public interface Ienumerator(T)
{
}
四、yield 关键字
foreach 语句对实现IEnumerable 或IEnumerable (T) 接口的数组或对象集合中的每个元素重复一组嵌入式语句。foreach 语句用于循环访问集合,以获取您需要的信息,但不能用于在源集合中添加或移除项,否则可能产生不可预知的副作用。如果需要在源集合中添加或移除项,请使用 for 循环。
嵌入语句为数组或集合中的每个元素继续执行。当为集合中的所有元素完成迭代后,控制传递给 foreach 块之后的下一个语句。
可以在 foreach 块的任何点使用 break 关键字跳出循环,或使用 continue 关键字进入循环的下一轮迭代。
foreach 循环还可以通过 goto、return 或 throw 语句退出。
四、创建迭代器
最常用方法:
对 IEnumerable 接口实现 GetEnumerator 方法。
public System.Collections. IEnumerable GetEnumerator()
{
for (int i = 0; i < 10; i++)
{
yield return i;
}
}
五、几种使用迭代器的方式
///
using System;
using System.Collections ;
using System.Collections.Generic;
using System.Text;
namespace IEnumberableTest
{
class Program
{
static void Main(string[] args)
{
myEnum enum1 = new myEnum(20);
foreach ( point p in enum1)
{
Console.WriteLine("("+p.x .ToString ()+","+p.y.ToString ()+","+p.z.ToString ()+")");
}
Console.Read();
}
}
//一个结构体,用于类myEnum
struct point
{
public int x;
public int y;
public int z;
}
//我们的一个派生于IEnumerable和IEnumerator接口的自定义类
class myEnum :IEnumerable,IEnumerator
{
//定义索引
private int index;
//定义一个point结构的数组
private point[] points;
//类的构造函数,用于初始化point结构数组
public myEnum(int numofpoint)
{
this.index = -1;
points = new point[numofpoint];
for (int i = 0; i < points.Length ; i++)
{
points[i].x = i;
points[i].y = i*i;
points[i].z = i*i*i;
}
}
//实现IEnumerable接口的GetEnumerator方法,返回一个IEnumerator,这里返回我们的自定义类,因为要对这个类的对象进行迭代
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
//实现IEnumerator接口的Reset方法,将集合索引置于第一个元素之前
public void Reset()
{
index = -1;
}
//实现IEnumerator接口的Current属性,返回一个自定义的point结构,即point数组的第index元素
public object Current
{
get
{
return points[index];
}
}
//实现IEnumerator接口的MoveNext方法,用于向前访问集合元素,如果超出集合范围,返回false
public bool MoveNext()
{
index++;
return index >= points.Length ? false : true;
}
}
}
//
// Declare the collection:
public class SampleCollection
{
public int[] items;
public SampleCollection()
{
items = new int[5] { 5, 4, 7, 9, 3 };
}
public System.Collections.IEnumerable BuildCollection()
{
for (int i = 0; i < items.Length; i++)
{
yield return items[i];
}
}
}
class MainClass
{
static void Main()
{
SampleCollection col = new SampleCollection();
// Display the collection items:
System.Console.WriteLine("Values in the collection are:");
foreach (int i in col.BuildCollection())
{
System.Console.Write(i + " ");
}
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
Values in the collection are:
5 4 7 9 3
*/
从下面的例子来分析IEnumerator与Ienumerable之间的关系
using System;
using System.Collections;
//一个人
public class Person
{
public Person(string fName, string lName)
{
this.firstName = fName;
this.lastName = lName;
}
public string firstName;
public string lastName;
}
//让列举的这些人可以被访问(IEnumerable动词形式)
public class People : IEnumerable
{
private Person[] _people;
public People(Person[] pArray)
{
_people = new Person[pArray.Length];
for (int i = 0; i < pArray.Length; i++)
{
_people[i] = pArray[i];
}
}
public IEnumerator GetEnumerator()
{
return new PeopleEnum(_people);
}
}
//列举多个人(IEnumerator名词形式)
public class PeopleEnum : IEnumerator
{
public Person[] _people;
// Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1;
public PeopleEnum(Person[] list)
{
_people = list;
}
public bool MoveNext()
{
position++;
return (position < _people.Length);
}
public void Reset()
{
position = -1;
}
public object Current
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
class App
{
static void Main()
{
Person[] peopleArray = new Person[3]
{
new Person("John", "Smith"),
new Person("Jim", "Johnson"),
new Person("Sue", "Rabon"),
};
People peopleList = new People(peopleArray);
foreach (Person p in peopleList)
Console.WriteLine(p.firstName + " " + p.lastName);
}
}
/* This code produces output similar to the following:
*
* John Smith
* Jim Johnson
* Sue Rabon
*
*/
六、特别注意
在 C# 中,集合类不一定要从 IEnumerable 和 IEnumerator 继承以便与 foreach 兼容。只要此类具有必需的 GetEnumerator、MoveNext、Reset 和 Current 成员,就可 foreach 与一起使用。省略接口有一个好处:您可以将 Current 的返回类型定义得比 Object 更为明确,从而提供类型安全。
省略 IEnumerable 和 IEnumerator 的缺点是,集合类不再能够与其他公共语言运行时兼容语言的 foreach 语句或等效项交互操作。
举例:
using System.Collections;
// Declare the Tokens class:
public class Tokens : IEnumerable
{
private string[] elements;
Tokens(string source, char[] delimiters)
{
// Parse the string into tokens:
elements = source.Split(delimiters);
}
// IEnumerable Interface Implementation:
// Declaration of the GetEnumerator() method
// required by IEnumerable
public IEnumerator GetEnumerator()
{
return new TokenEnumerator(this);
}
// Inner class implements IEnumerator interface:
private class TokenEnumerator : IEnumerator
{
private int position = -1;
private Tokens t;
public TokenEnumerator(Tokens t)
{
this.t = t;
}
// Declare the MoveNext method required by IEnumerator:
public bool MoveNext()
{
if (position < t.elements.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}
// Declare the Reset method required by IEnumerator:
public void Reset()
{
position = -1;
}
// Declare the Current property required by IEnumerator:
public object Current
{
get
{
return t.elements[position];
}
}
}
// Test Tokens, TokenEnumerator
static void Main()
{
// Testing Tokens by breaking the string into tokens:
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});
foreach (string item in f)
{
System.Console.WriteLine(item);
}
}
}
/* Output:
This
is
a
sample
sentence.
*/