枚举数与可枚举类型(笔记)
要使用foreach遍历类,必须让类实现IEnumerable接口,并且创建一个继承了Enumerator的类接收IEnumerable接口中GetEnumerator()方法的返回值.
那为什么数组可以直接用foreach遍历其中的数组的项呢?
因为在声明数组时.net已经隐式的让数组继承了IEnumertabel接口,并且创建了一个继承了IEnumramertor接口的类.(猜想)
那么现在假设Person类有一个记忆功能,现在我想用foreach遍历person类读取,记忆中的数据,并把数据显示出来..
所以我先声明一个Person类,他有Name,Age,Memory字段,还有一个构造函数以及一个See方法,模拟人从外界得到记忆,并实现了IEnumerable接口,
now,let us begin...
class Person
{
privatestring name;
privateint age;
private List<string> memory = new List<string>();
publicstring Name
{
get
{
return name;
}
}
publicint Age
{
get
{
return age;
}
}
publicstring[] Memory
{
get
{
return
memory.ToArray();
}
}
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
publicvoid See(string data)
{
memory.Add(data);
}
publicvoid See(string[] data)
{
memory.AddRange(data);
}
}
//现在如果我们要直接遍历p中的记忆并等到他的记忆,是没有办法的。
staticvoid Main(string[] args)
{
//假设这些就是外界记忆
string[] data = { "sky", "ok", "mother", "father", "good", "wonderful" };
Person p = new Person("tom", 18);
//将p记住了很多单词
p.See(data);
//p在又一次记住了一个新的单词
p.See("wather");
//现在如果我们先要直接遍历p中的记忆并等到他的记忆,是没有办法的。
foreach (string item in p)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
上面的代码会报错:
错误 1 “枚举数和迭代器.Person”不包含“GetEnumerator”的公共定义,因此 foreach 语句不能作用于“枚举数和迭代器.Person”类型的变量 C:\Users\Administrator.think-THINK\Documents\Visual Studio 2008\Projects\c sharp图解教程\枚举数和迭代器\Program.cs 30 13 枚举数和迭代器
所以我们要让Person类实现IEnumerable接口,IEnumerable接口中有且只有一个GetEnumerator方法,该方法返回IEnumerator类型参数,所以我们要创建了一个继承了IEnumramertor接口的类.用来接收GetEnumerator方放得返回值.
class Person:IEnumerable
{
privatestring name;
privateint age;
private List<string> memory = new List<string>();
publicstring Name
{
get
{
return name;
}
}
publicint Age
{
get
{
return age;
}
}
publicstring[] Memory
{
get
{
return
memory.ToArray();
}
}
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
publicvoid See(string data)
{
memory.Add(data);
}
publicvoid See(string[] data)
{
memory.AddRange(data);
}
public
IEnumerator GetEnumerator()
{
returnnew PersonEnumerator(memory); //将需要遍历的东东作为参数传入, 如memory;
}
}
class
PersonEnumerator : IEnumerator //定义类PersonEnumerator, 作为枚举器
{
List<string>
data = new List<string>();
public
PersonEnumerator(List<string>
list)
{
data = list;
}
privateint positon = -1;
publicobject Current
{
get
{
return data[positon];
}
}
publicbool MoveNext()
{
positon++;
return positon <
data.Count;
}
publicvoid Reset()
{
positon = -1;
}
}
在此运行代码
staticvoid Main(string[] args)
{
//假设这些就是外界记忆
string[] data = { "sky", "ok", "mother", "father", "good", "wonderful" };
Person p = new Person("tom", 18);
//将p记住了很多单词
p.See(data);
//p在又一次记住了一个新的单词
p.See("wather");
//现在可行了,因为我们Person实现了IEnumerable接口,并且创建了一个用于接收IEnumramerable方法的继承IEnumerator的类
foreach (string item in p)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
为什么数组可以直接用foreach遍历其中的item呢?
因为在声明数组时.net已经隐式的让数组继承了IEnumertabel接口,并且创建了一个继承了IEnumramertor接口的类.(猜想)
现在我们来模拟下foreach是如何工作的
staticvoid Main(string[] args)
{
string[] data = { "sky", "ok", "mother", "father", "good", "wonderful" };
Person p = new Person("tom", 18);
p.See(data);
p.See("wather");
//现在让我们模拟foreach是如何工作的
IEnumerable
ieble = (IEnumerable)p;
IEnumerator
itor = ieble.GetEnumerator();
while (itor.MoveNext())
{
string item = (string)itor.Current;
Console.WriteLine(item);
}
Console.ReadKey();
}
结果跟上面的一样。。
完全的代码如下:
1staticvoid Main(string[] args)
2
{
3
4
string[] data = { "sky", "ok", "mother", "father", "good", "wonderful" };
5
Person p = new Person("tom", 18);
6
p.See(data);
7
p.See("wather");
8
//现在如果我们先要直接遍历p中的记忆并等到他的记忆,是没有办法的。
9//所以我们让person实现了Ienumrabel接口,并且创建一个继承了IEnumerator接口的类来接收
IEnumerable方法的返回值,因此我们终于可以用foreach遍历p,得到p 的记忆
10//为什么数组可以直接用foreach遍历其中的item呢?
11//因为在声明数组时.net已经隐式的为数组让数组继承了IEnumertabel接口,并且创建了一个继承了IEnumramertor接口的类.
12
foreach (string item in p)
13
{
14
Console.WriteLine(item);
15
}
16
17 //现在让我们模拟foreach是如何工作的
18 //其实这里利用了多态的性质,因为Person继承了IEnumerable接口,所以可以通过接口变量来调用GetEnumerator()方法,这是有理由的...foreach不可能知道你传递过来的是数据是什么类型的,如果你直接用Person来调用,那下次传递过来的是Dog类.那foreach就不能工作了
19
IEnumerable ieble = (IEnumerable)p; //将实例对象P转为IEnumerator接口类型赋给变更ieble, 以便用接口类型变量调用GetEnumerator(), 避免后续用实例对象P调用GetEnumerator(), 原因如18行描述.
20 //为什么不用这个的原因,如上..
21 //p.GetEnumerator();
22
IEnumerator itor = ieble.GetEnumerator();//这里也利用了多态,为什么不用PersonEnumerator,而用接口变量,理由是一样的...
23//上21行程序调用流程ieble.GetEnumerator()->构造函数p. PersonEnumerator(memory), 返回PersonEnumerator类型实例对象, 并隐式转为IEnumerator接口类型, 赋值给IEnumerator接口类型变量itor.以便后期程序可通过itor调用PersonEnumerator类型中的方法, MoveNext(), Current(), Reset(),
也避免后续用返回PersonEnumerator类型实例对象调用PersonEnumerator类型中的方法, MoveNext(),
Current(), Reset(); 原因如18行描述
24
while
(itor.MoveNext())
25
{
26
string item = (string)itor.Current;
27
Console.WriteLine(item);
28
}
29
30
31
Console.ReadKey();
32 }
33
}
34 //那么现在假设Person类有一个记忆功能,现在我想用foreach遍历person类读取,记忆中的数据,并把数据显示出来..
35 //所以我先声明一个Person类,他有Name,Age,Memory字段,还有一个构造函数以及一个See方法,模拟人从外界得到记忆,并实现了IEnumerable接口,now,let us begin...
36
37
class
Person:IEnumerable
38
{
39 privatestring name;
40
privateint age;
41
private List<string> memory = new List<string>();
42
publicstring Name
43
{
44
get
45
{
46
return name;
47
}
48 }
49
50
publicint Age
51
{
52
get
53
{
54
return age;
55
}
56
}
57
58
publicstring[] Memory
59
{
60
get
61
{
62 return
memory.ToArray();
63
}
64
}
65
66
public Person(string name, int age)
67
{
68
this.name = name;
69
this.age = age;
70
}
71
72
publicvoid See(string data)
73
{
74
memory.Add(data);
75
}
76
77
publicvoid See(string[] data)
78
{
79
memory.AddRange(data);
80
}
81
82
public IEnumerator GetEnumerator()
83
{
84 returnnew PersonEnumerator(memory); //将需要遍历的东东作为参数传入构造函数并初始化枚举器,如memory;
85
}
86
}
87
88
class PersonEnumerator
: IEnumerator //定义类PersonEnumerator, 作为枚举器
89 {
90
List<string> data = new List<string>();
91
public
PersonEnumerator(List<string> list)
92
{
93
data = list;
94
}
95
privateint positon = -1;
96
publicobject Current
97
{
98
get
99
{
100
return data[positon];
101
}
102
}
103
104
publicbool MoveNext()
105
{
106
positon++;
107
return positon <
data.Count;
108
}
109
110
publicvoid Reset()
111
{
112
positon = -1;
113
}
114
}
附件列表