CSharp迭代器模式
1、迭代器模式在CSharp语法中非常常见,数据结构类都继承了IEnumerable接口,以此获取foreach语法糖支持。foreach语法糖本质是使用IEnumerator接口的MoveNext方法进行遍历,直到MoveNext返回值为-1。
2、此外CSharp还有yield return和yield break这两个语法糖,使用过Unity的协程的同学应该对此很熟悉。yield return可以理解为将后续元素加入IEnumerator接口内部的存储数组内,yield break表示不进行后续操作。
3、但编译器(使用ILSpy反编译查看,C#版本设为1.0)对yield return语法糖的实际上做法是:生成一个迭代器方法B,将原方法A的this传递到方法B,在MoveNext方法内生成相应的代码,具体可见下方代码:
ClassA有方法EnumTest,进行了一些yield return操作
class ClassA
{
public int a;
ClassA classA = new ClassA() { a = 1 };
IEnumerator EnumTest()
{
yield return classA;
yield return 1;
yield return null;
yield return new ClassA();
}
}
编译器生成的代码,自动生成了一个<EnumTest>d__2方法,用于EnumTest的迭代操作
internal class ClassA
{
[CompilerGenerated]
private sealed class <EnumTest>d__2 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public ClassA <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <EnumTest>d__2(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
}
private bool MoveNext()
{
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = <>4__this.classA;
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
<>2__current = 1;
<>1__state = 2;
return true;
case 2:
<>1__state = -1;
<>2__current = null;
<>1__state = 3;
return true;
case 3:
<>1__state = -1;
<>2__current = new ClassA();
<>1__state = 4;
return true;
case 4:
<>1__state = -1;
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
public int a;
private ClassA classA;
[IteratorStateMachine(typeof(<EnumTest>d__2))]
private IEnumerator EnumTest()
{
<EnumTest>d__2 <EnumTest>d__ = new <EnumTest>d__2(0);
<EnumTest>d__.<>4__this = this;
return <EnumTest>d__;
}
public ClassA()
{
ClassA obj = new ClassA();
obj.a = 1;
classA = obj;
base..ctor();
}
}
可以调用Test方法查看迭代器的内容
public void Test()
{
IEnumerator enumerator = EnumTest();
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current);
}
}
此外还可以自己手动实现迭代器
外部调用接口 IMyEnumerable
public interface IMyEnumerable:IEnumerable
{
}
迭代器实现接口 IMyEnumerator
public interface IMyEnumerator:IEnumerator
{
}
迭代器实现结构体,继承IMyEnumator
public struct MyEnumerator : IMyEnumerator
{
MyList myList;
int index;
public MyEnumerator(MyList myList)
{
this.myList = myList;
this.index = -1;
current = null;
}
private object current;
public object Current => current;
public bool MoveNext()
{
if (index >= myList.Count - 1)
{
return false;
}
else
{
index += 1;
current = myList[index];
return true;
}
}
public void Reset()
{
index = -1;
current = null;
}
}
自定义数据结构 MyList,继承外部调用接口IMyEnumerable
public class MyList: IMyEnumerable
{
IMyEnumerator myEnumerator;
object[] objects;
public int Count { private set; get; }
public MyList() : this(10)
{
}
public MyList(int maxCount)
{
objects = new object[maxCount];
Count = objects.Length;
}
public object this[int i]
{
get
{
return objects[i];
}
set
{
objects[i]= value;
}
}
public IMyEnumerator GetEnumerator()
{
if (myEnumerator == null)
{
myEnumerator = new MyEnumerator(this);
}
return myEnumerator;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
使用方法,和普通数据结构一样使用MyList类,加入数据
,然后使用foreach遍历数据,最后不使用语法糖遍历数据。
static void Main(string[] args)
{
MyList myList = new MyList(3);
myList[0] = 1;
myList[1] = 2;
myList[2] = 3;
//==============使用语法糖遍历数据
foreach (var item in myList)
{
Console.WriteLine(item);
}
//=============不使用语法糖遍历数据
IMyEnumerator myEnumerator = myList.GetEnumerator();
while (myEnumerator.MoveNext())
{
Console.WriteLine(myEnumerator.Current);
}
}