C#协程的深入挖掘:
要弄懂协程,首先要明白枚举器和迭代器的区别:
- 枚举器:
- ①foreach的本质,一个实现了IEnumerable接口的类的实例可以用foreach遍历。
- Why——因为IEnumerable接口中定义了一个方法,这个方法返回一个IEnumerator类型对象。
- ★(Enumerator)枚举器可以依次返回请求的数组中的元素,枚举器知道项的次序并且跟踪它在序列中的位置。依次返回请求的当前项。但枚举器只允许访问集合中的数据,无法修改集合中的数据。
- ②IEnumrator接口
- IEnumrator接口包含了3个函数成员:Current、MoveNext以及Reset;
- .Current是返回序列中当前位置项的属性。(注意:Current它是只读属性,它返回Object类型的引用,所以可以返回任意类型)
- .MoveNext是把枚举器位置前进到集合中下一项的方法。它返回布尔值,指示新的位置是否是有效位置。
- 枚举器的原始位置在序列中的第一项之前,因此MoveNext必须在第一次使用Current之前调用。
- .Reset是把位置重置为原始状态的方法。
- ③IEnumerable接口
- 数组是可枚举类型,是因为实现了IEnumerable接口的类,所以可枚举类都是因为实现了IEnumerable接口的类。
- IEnumerable接口只有一个成员——GetEnumerator()方法,它返回对象的枚举器。
using System;
using System.Collections;
// 创建枚举器
class ColorEnumerator : IEnumerator
{
string[] _colors; // 用于存储内部的 color 数组
int _position = -1; // 用于表示枚举器位置
// 构造函数
public ColorEnumerator(string[] theColors)
{
_colors = new string[theColors.Length];
for (int i = 0; i < theColors.Length; i++)
{
_colors[i] = theColors[i];
}
}
// 实现 Current
public object Current
{
get
{
if (_position == -1)
{
throw new InvalidOperationException();
}
if (_position >= _colors.Length)
{
throw new InvalidOperationException();
}
return _colors[_position];
}
}
// 实现MoveNext
public bool MoveNext()
{
if (_position < _colors.Length - 1)
{
_position++;
return true;
}
else
{
return false;
}
}
// 实现 Reset
public void Reset()
{
_position = -1;
}
}
// 可枚举类,实现 IEnumrable 接口,提供 GetEnumerator
class ColorBase : IEnumerable
{
string[] Colors = { "violet", "blue", "cyan", "green" };
public IEnumerator GetEnumerator()
{
return new ColorEnumerator(Colors);
}
}
class Program
{
static void Main()
{
ColorBase cb = new ColorBase();
foreach (string color in cb)
{
Console.WriteLine(color);
}
}
}
- 拓展:泛型枚举接口IEnumerable<T>和IEnumerator<T>,我们更应该使用泛型的枚举接口。
- Why——因为IEnumerable的GetEnumerator方法返回IEnumerator枚举类的实例,而IEnumerator枚举类里实现了Current属性(一个object类型),所以在使用时存在拆箱操作(损耗性能),而泛型的IEnumerator<T>枚举类直接返回实际类型的对象。并且只要集合不变,枚举器就有效,但集合一旦发生改变,则枚举器会失效(和C++的迭代器一样)
- 迭代器:
- 迭代器是C#2.0引入的,使用yield关键字让编译器代替我们完成了枚举类型和枚举器的创建。
//迭代器返回一个泛型枚举器(并没有实现IEnumerator接口的Reset方法)
public IEnumerator<string> GetEnumeratorTwo(){
yield return "violet";
yield return "blue";
yield return "cyan";
yield return "green";
}
class MyClass{//可枚举类型
public IEnumerator<string> GetEnumerator(){
return GetEnumeratorTwo();
}
}
本文深入解析了C#协程中的枚举器和迭代器概念,介绍了它们的工作原理、用途,并通过实例展示了如何使用和它们之间的差异。重点讲解了foreach遍历背后的IEnumerable接口和IEnumerator接口,以及迭代器带来的便利和性能优势。
12万+

被折叠的 条评论
为什么被折叠?



