迭代器模式是設計模式的一種,由於其運用的廣泛性,不少語言都有內嵌的原生支持設計模式
在.NET中,迭代器模式是經過IEnumerator、IEnumerable兩個接口(有非泛型和泛型2種版本)來封裝的api
迭代器模式的一個重要方面是:不是一次返回全部數據,而是每次調用只返回一個元素函數
Array、IEnumerable和IEnumerator之間關係以下: this
foreach遍歷spa
① Array、集合容器類派生於IEnumerable接口類(該類中含有一個IEnumerator GetEnumerator()接口函數),Array、集合容器類實現了該函數,這使得foreach可對其進行遍歷設計
注:不須要從IEnumerable派生,只要類實現了IEnumerator GetEnumerator()函數,就能夠使用foreach遍歷該類中的元素code
② IEnumerator定義了Current屬性來返回遊標所在的元素,MoveNext方法移動到下一個元素(如有元素則返回true,若到達末尾則返回false),Reset方法是將遊標重置到第一項的位置blog
int[] IntArray = new int[] { 1, 2, 3 }; foreach (int n in IntArray) { Console.WriteLine(n); } // 上面的foreach等價於下方的代碼實現 IEnumerator e = IntArray.GetEnumerator(); try { while (e.MoveNext()) { Console.WriteLine((int)e.Current); } } finally { var disposable = e as IDisposable; if (disposable != null) { disposable.Dispose(); } }
在C#1.0中,建立IEnumerator枚舉器須要寫大量的代碼。C#2.0添加了yield語句,讓編譯器自動建立IEnumerator枚舉器。接口
yield return語句返回集合的一個元素,並移動到下一個元素上。yield break可中止迭代。get
非泛型版本IEnumerator
class EnumeratorTest { public IEnumerator GetEnumerator() { yield return 100; yield return "Good"; } } EnumeratorTest eTest = new EnumeratorTest(); foreach (object o in eTest) { Console.WriteLine(o); }
編譯後生成的代碼以下:
class EnumeratorTest { public IEnumerator GetEnumerator() { return new GenerateEnumerator(0); } private sealed class GenerateEnumerator : IEnumerator<object>, IEnumerator, IDisposable { // Fields private int state; private object current; // Methods public GenerateEnumerator(int state) { this.state = state; } bool IEnumerator.MoveNext() { switch (this.state) { case 0: this.state = -1; this.current = 100; this.state = 1; return true; case 1: this.state = -1; this.current = "Good"; this.state = 2; return true; case 2: this.state = -1; break; } return false; } void IEnumerator.Reset() { throw new NotSupportedException(); } void IDisposable.Dispose() { } // Properties object IEnumerator<object>.Current { get { return this.current; } } object IEnumerator.Current { get { return this.current; } } } } EnumeratorTest eTest = new EnumeratorTest(); IEnumerator e = eTest.GetEnumerator(); try { while (e.MoveNext()) { Console.WriteLine(e.Current); } } finally { var disposable = e as IDisposable; if (disposable != null) { disposable.Dispose(); } }
泛型版本IEnumerator<T>
class EnumeratorTest2 { private bool m_bBreak; public EnumeratorTest2(bool bBreak) { m_bBreak = bBreak; } public IEnumerator<string> GetEnumerator() { yield return "Hello"; if (m_bBreak) { yield break; } yield return "World"; } } EnumeratorTest2 eTest2 = new EnumeratorTest2(true); IEnumerator<string> e2 = eTest2.GetEnumerator(); while (e2.MoveNext()) { Console.WriteLine(e2.Current); }
編譯後生成的代碼以下:
class EnumeratorTest2 { private bool m_bBreak; public EnumeratorTest2(bool bBreak) { m_bBreak = bBreak; } public IEnumerator<string> GetEnumerator() { GenerateEnumerator2 e2 = new GenerateEnumerator2(0); e2.eTest2 = this; return e2; } private sealed class GenerateEnumerator2 : IEnumerator<string>, IEnumerator, IDisposable { // Fields private int state; private string current; public EnumeratorTest2 eTest2; // Methods public GenerateEnumerator2(int state) { this.state = state; } bool IEnumerator.MoveNext() { switch (this.state) { case 0: this.state = -1; this.current = "Hello"; this.state = 1; return true; case 1: this.state = -1; if (eTest2.m_bBreak) { break; } this.current = "World"; this.state = 2; return true; case 2: this.state = -1; break; } return false; } void IEnumerator.Reset() { throw new NotSupportedException(); } void IDisposable.Dispose() { } // Properties string IEnumerator<string>.Current { get { return this.current; } } object IEnumerator.Current { get { return this.current; } } } } EnumeratorTest2 eTest2 = new EnumeratorTest2(true); IEnumerator<string> e2 = eTest2.GetEnumerator(); while (e2.MoveNext()) { Console.WriteLine(e2.Current); }
非泛型版本IEnumerable
class EnumeratorTest3 { public IEnumerable Test1() { yield return 100; yield return 200; } } EnumeratorTest3 eTest3 = new EnumeratorTest3(); foreach (object o in eTest3.Test1()) { Console.WriteLine(o); }
編譯後生成的代碼以下:
class EnumeratorTest3 { public IEnumerable Test1() { return new GenerateEnumerable3(0); } private sealed class GenerateEnumerable3 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable { // Fields private int state; private int current; // Methods public GenerateEnumerable3(int state) { this.state = state; } bool IEnumerator.MoveNext() { switch (this.state) { case 0: this.state = -1; this.current = 100; this.state = 1; return true; case 1: this.state = -1; this.current = 200; this.state = 2; return true; case 2: this.state = -1; break; } return false; } IEnumerator<object> IEnumerable<object>.GetEnumerator() { return this; } IEnumerator IEnumerable.GetEnumerator() { return this; } void IEnumerator.Reset() { throw new NotSupportedException(); } void IDisposable.Dispose() { } // Properties object IEnumerator<object>.Current { get { return this.current; } } object IEnumerator.Current { get { return this.current; } } } } EnumeratorTest3 eTest3 = new EnumeratorTest3(); IEnumerator e3 = eTest3.Test1().GetEnumerator(); while (e3.MoveNext()) { Console.WriteLine(e3.Current); }
泛型版本IEnumerable<T>
class EnumeratorTest4 { private bool m_bBreak; public EnumeratorTest4(bool bBreak) { m_bBreak = bBreak; } public IEnumerable<float> Test1() { yield return 1.0f; if (m_bBreak) { yield break; } yield return 3.0f; } } EnumeratorTest4 eTest4 = new EnumeratorTest4(true); foreach (object o in eTest4.Test1()) { Console.WriteLine(o); }
編譯後生成的代碼以下:
class EnumeratorTest4 { private bool m_bBreak; public EnumeratorTest4(bool bBreak) { m_bBreak = bBreak; } public IEnumerable<float> Test1() { GenerateEnumerable4 e4 = new GenerateEnumerable4(0); e4.eTest4 = this; return e4; } private sealed class GenerateEnumerable4 : IEnumerable<float>, IEnumerable, IEnumerator<float>, IEnumerator, IDisposable { // Fields private int state; private float current; public EnumeratorTest4 eTest4; // Methods public GenerateEnumerable4(int state) { this.state = state; } bool IEnumerator.MoveNext() { switch (this.state) { case 0: this.state = -1; this.current = 1.0f; this.state = 1; return true; case 1: this.state = -1; if (this.eTest4.m_bBreak) { break; } this.current = 3.0f; this.state = 2; return true; case 2: this.state = -1; break; } return false; } IEnumerator<float> IEnumerable<float>.GetEnumerator() { return this; } IEnumerator IEnumerable.GetEnumerator() { return this; } void IEnumerator.Reset() { throw new NotSupportedException(); } void IDisposable.Dispose() { } // Properties float IEnumerator<float>.Current { get { return this.current; } } object IEnumerator.Current { get { return this.current; } } } } EnumeratorTest4 eTest4 = new EnumeratorTest4(true); IEnumerator<float> e4 = eTest4.Test1().GetEnumerator(); while (e4.MoveNext()) { Console.WriteLine(e4.Current); }