黑马程序员 枚举数和迭代器 总结
来源:互联网 发布:ubuntu安装 分区 编辑:程序博客网 时间:2024/05/18 19:40
1.为什么数组可以使用foreach遍历。原因是数组可以按需提供一个叫做枚举数的对象。枚举数可以依次返回请求的数组元素。
我的话说就是:数组实现了一个叫IEnumerable的接口,该接口有一个方法GetEnumerator(); 该方法返回一个实现了IEnumerator接口的对象,利用该对象可以依次取出这个数组的每个值。
2.foreach 结构被设计用来和可枚举类型一起使用。只要给它的遍历对象是可枚举类型,比如数组,它就会执行如下行为:通过调用GetEnumerator方法获取对象的枚举数;
从枚举数中请求每一项把它作为迭代变量,代码可以读但不可以改变。
3.IEnumerator接口
IEnumerator接口包含3个函数成员:Current、MoveNext、以及Reset
Current返回序列中当前位置项的属性。
MoveNext是把枚举位置前进到集合中下一项的方法。它也返回布尔值,指示新的位置是有效位置或已经超过了序列的尾部。
4.IEnumerable接口只有一个成员——GetEnumerator方法,它返回对象的枚举数。
5.我们来看一个自己实现枚举数的例子:
class ColorEnumerator : IEnumerator
{
string[] Colors;
int Position = -1;
public ColorEnumerator(string[] theColors)
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
{
Colors[i] = theColors[i];
}
}
public object Current
{
get
{
if(Position == -1 || Position == Colors.Length)
throw new NotImplementedException();
return Colors[Position];
}
}
public bool MoveNext()
{
if (Position < Colors.Length - 1)
{
Position++;
return true;
}
else
return false;
}
public void Reset()
{
Position = -1;
}
}
class MyColors : IEnumerable
{
string[] Colors = { "Red","Yellow","Blue"};
public IEnumerator GetEnumerator()
{
return new ColorEnumerator(Colors);
}
}
class Program
{
static void Main(string[] args)
{
MyColors mc = new MyColors();
foreach (string color in mc)
{
Console.WriteLine(color);
}
Console.ReadKey();
}
}
6.IEnumerator<T>接口
IEnumerator<T>接口使用泛型来返回实际的类型,而不是Object类型的引用。
IEnumerator<T>接口从另外两个接口继承——非泛型IEnumerator接口和IDisposable接口。实现成员:
IDisposable 接口只有一个叫做Dispose的类型为void的无参方法,它可以用来释放由类占据的非托管资源
IEnumerator<T>接口本身只有一个Current特性,它返回类型T或它衍生的项的实例——不是ojbect类型的引用。
由于IEnumerator<T>和IEnumerator都有一个叫做Current的成员,我们应该显式实现IEnumerator版本,然后在类中实现泛型版本。
7.IEnumerable<T>接口
泛型版本从IEnumerator继承,所以也必须实现IEnumerable接口
与IEnumerable差不多,泛型版本也包含了一个方法——GetEnumertor。然而,这个版本的GetEnumerator实现泛型IEnumerator<T>接口的类对象。
由于类必须实现两个GetEnumerator方法,我们需要显式实现非泛型版本,并在类中实现泛型版本。
8.用泛型接口实现的迭代器,示例:
class ColorEnumerator : IEnumerator<string>
{
string[] Colors;
int Position = -1;
public ColorEnumerator(string[] theColors)
{
Colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
{
Colors[i] = theColors[i];
}
}
object IEnumerator.Current
{
get
{
if(Position == -1 || Position == Colors.Length)
throw new NotImplementedException();
return Colors[Position];
}
}
public bool MoveNext()
{
if (Position < Colors.Length - 1)
{
Position++;
return true;
}
else
return false;
}
public void Reset()
{
Position = -1;
}
public void Dispose()
{
//throw new NotImplementedException();
}
public string Current
{
get
{
if (Position == -1 || Position == Colors.Length)
throw new NotImplementedException();
return Colors[Position];
}
}
}
class MyColors : IEnumerable<string>
{
string[] Colors = { "Red","Yellow","Blue"};
public IEnumerator<string> GetEnumerator()
{
return new ColorEnumerator(Colors);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new ColorEnumerator(Colors);
}
}
class Program
{
static void Main(string[] args)
{
MyColors mc = new MyColors();
foreach (string color in mc)
{
Console.WriteLine(color);
}
Console.ReadKey();
}
}
9.迭代器:
迭代器就是为我们简化创建迭代数的东西,我们不用再外写一个实现IEnumerator接口的枚举器了,现在只要在我们的类中简单写一个方法可以返回IEnumerator类型(使用yield return 这叫迭代器),再实现IEnumerable接口, GetEnumerator方法中调迭代器就可。 实际上,这是编译器帮我们简化了,再编译时编译器还是创建了枚举器。
迭代器示例:
class Myclass
{
public IEnumerator<string> GetEnumerator()
{
return BlackAndWhite();
}
public IEnumerator<string> BlackAndWhite()
{
yield return "black";
yield return "glay";
yield return "white";
}
}
class Program
{
static void Main(string[] args)
{
Myclass myC = new Myclass();
foreach (string str in myC)
{
Console.WriteLine(str);
}
Console.ReadKey();
}
}
其实foreach迭代时,那个类只需有GetEnumerator方法(public 无参)就行,所以自己创建枚举器时,类名后也可以不加 : IEnumerable。 还可以使用迭代器来创建可枚举类型,BlackAndWhite还可以返回IEnumerable<string>,等各种玩法。在foreach中还可以直接调用BlackAndWhite方法,因为它返回的是可枚举类型,如下:
class Myclass
{
public IEnumerator<string> GetEnumerator()
{
return BlackAndWhite().GetEnumerator();
}
public IEnumerable<string> BlackAndWhite()
{
yield return "black";
yield return "glay";
yield return "white";
}
}
class Program
{
static void Main(string[] args)
{
Myclass myC = new Myclass();
foreach (string str in myC)
{
Console.WriteLine(str);
}
foreach (string str in myC.BlackAndWhite())
{
Console.WriteLine(str);
}
Console.ReadKey();
}
}
比较两种迭代模式:
1.如果实现GetEnumerator,它调用迭代器方法以获取自动生成的实现IEnumerable的类实例。然后,从IEnumerator对象返回由GetEnumerable对象返回由GetEumerator创建的枚举数。
2.如果通过不实现GetEnumerator使类本身不可被枚举,仍然可以使用由迭代器返回的可枚举类,只需要直接调用迭代器方法。
我们可使用第2种模式不实现GetEnumerator,直接调用迭代器方法可以写多个可枚举类型。
还可以使用属性产生多个枚举数:
{
class Myclass :IEnumerable<string>
{
bool ColorFlag = false;
public Myclass(bool flag)
{
ColorFlag = flag;
}
IEnumerator<string> BlackAndWhite
{
get
{
yield return "black";
yield return "glay";
yield return "white";
}
}
IEnumerator<string> Colors
{
get
{
string[] theColors = { "blue", "red", "yellow"};
for(int i=0;i<theColors.Length;i++)
yield return theColors[i];
}
}
public IEnumerator<string> GetEnumerator()
{
return ColorFlag
? Colors
: BlackAndWhite;
}
IEnumerator IEnumerable.GetEnumerator() //IEnumerator需要引用命名空间System.Collections;
{
return ColorFlag
? Colors
: BlackAndWhite;
}
}
class Program
{
static void Main(string[] args)
{
Myclass myC = new Myclass(true);
foreach (string str in myC)
{
Console.WriteLine(str);
}
Console.ReadKey();
}
}
10.迭代器实质
由编译器生成的枚举数类是有4个状态的状态机。
Before 首次调用MoveNext的初始状态
Running 调用MoveNext后时入这个状态。在这个状态中,枚举数检测并设置下一项的位置,在遇到yield rturn 、yield brdak或在迭代器体结束时,退出状态。
Suspended 状态机等待下次调用MoveNext的状态。
After 没有更多项可以枚举
- 黑马程序员 枚举数和迭代器 总结
- 黑马程序员12——枚举数和迭代器
- 黑马程序员_JAVA_枚举和反射总结
- 黑马程序员,枚举总结
- 黑马程序员_枚举总结
- 黑马程序员-java枚举总结
- 黑马程序员---枚举学习总结
- 黑马程序员_枚举和泛型总结
- 黑马程序员-枚举和注解
- 黑马程序员:枚举和结构
- C# 枚举数和迭代器总结
- 黑马程序员_Java中的枚举总结
- 黑马程序员:Java基础总结----枚举
- 黑马程序员——枚举学习总结
- 黑马程序员 关于枚举类型总结
- 枚举数和迭代器(1)--枚举数
- 黑马程序员训练营--结构和枚举
- 黑马程序员--学习--高新技术--枚举和反射
- 黑马程序员 接口 总结
- 工厂三兄弟之抽象工厂模式(一)
- 黑马程序员——一个面对对象的小实例
- 栈帧
- Huffman 编码
- 黑马程序员 枚举数和迭代器 总结
- QoS令牌桶
- 黑马程序员 委托、方法、事件 总结
- html5 canvas制作箭头
- 【ASO潜规则】之改名克隆 疯狂圈钱
- 黑马程序员——Foreach的原理
- 工厂三兄弟之抽象工厂模式(二)
- RelativeLayout用到的一些重要的属性
- iOS webservice+soap