迭代器模式的原始图如下:
事例代码:
class Program { static void Main(string[] args) { ConAggregate<string> ca = new ConAggregate<string>(); ca.Datas = new string[] { "sdf","wefwe","efwfw","swsdfw"}; foreach (var test in ca.Datas) { Console.WriteLine(test); } } } public abstract class Aggegate<T> { public abstract ITerator<T> GeTerator(); } public class ConAggregate<T> : Aggegate<T> { public T[] Datas { set; get; } public override ITerator<T> GeTerator() { return new ConIterator<T>(this); } } public interface ITerator<out T> { void Reset(); bool MoveNext(); T CurrentItem { get; } } public class ConIterator<T> : ITerator<T> { private ConAggregate<T> ct; int position = -1; public ConIterator(ConAggregate<T> c) { ct = c; } public T CurrentItem { get { return ct.Datas[position]; } } public void Reset() { position = -1; } public bool MoveNext() { position++; return position < ct.Datas.Length; } }
c# 有IEnumerable,IEnumerator 两个接口 实现这两个接口 既可完成迭代。即可以使用Foreach 做遍历。 引用MSDN里容器代码:
class Program { static void Main(string[] args) { BoxCollection bxList = new BoxCollection(); bxList.Add(new Box(10, 4, 6)); bxList.Add(new Box(4, 6, 10)); bxList.Add(new Box(6, 10, 4)); bxList.Add(new Box(12, 8, 10)); bxList.Add(new Box(10, 4, 6)); foreach (Box bx in bxList) { Console.WriteLine("{0}\t{1}\t{2}\t{3}", bx.Height.ToString(), bx.Length.ToString(), bx.Width.ToString(), bx.GetHashCode().ToString()); } } } public class Box { public Box(int h, int l, int w) { this.Height = h; this.Length = l; this.Width = w; } public int Height { get; set; } public int Length { get; set; } public int Width { get; set; } public override int GetHashCode() { return base.GetHashCode(); } } public class BoxCollection : IEnumerable<Box> { // The generic enumerator obtained from IEnumerator<Box> // by GetEnumerator can also be used with the non-generic IEnumerator. // To avoid a naming conflict, the non-generic IEnumerable method // is explicitly implemented. public IEnumerator<Box> GetEnumerator() { return new BoxEnumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new BoxEnumerator(this); } // The inner collection to store objects. private List<Box> innerCol; public BoxCollection() { innerCol = new List<Box>(); } // Adds an index to the collection. public Box this[int index] { get { return (Box)innerCol[index]; } set { innerCol[index] = value; } } // Determines if an item is in the collection // by using the BoxSameDimensions equality comparer. public bool Contains(Box item) { bool found = false; foreach (Box bx in innerCol) { // Equality defined by the Box // class's implmentation of IEquitable<T>. if (bx.Equals(item)) { found = true; } } return found; } public bool Contains(Box item, EqualityComparer<Box> comp) { bool found = false; foreach (Box bx in innerCol) { if (comp.Equals(bx, item)) { found = true; } } return found; } public void Add(Box item) { if (!Contains(item)) { innerCol.Add(item); } else { Console.WriteLine("A box with {0}x{1}x{2} dimensions was already added to the collection.", item.Height.ToString(), item.Length.ToString(), item.Width.ToString()); } } public void Clear() { innerCol.Clear(); } public void CopyTo(Box[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException("The array cannot be null."); if (arrayIndex < 0) throw new ArgumentOutOfRangeException("The starting array index cannot be negative."); if (Count > array.Length - arrayIndex + 1) throw new ArgumentException("The destination array has fewer elements than the collection."); for (int i = 0; i < innerCol.Count; i++) { array[i + arrayIndex] = innerCol[i]; } } public int Count { get { return innerCol.Count; } } public bool IsReadOnly { get { return false; } } } public class BoxEnumerator : IEnumerator<Box> { private BoxCollection _collection; private int curIndex; private Box curBox; public BoxEnumerator(BoxCollection collection) { _collection = collection; curIndex = -1; curBox = default(Box); } public bool MoveNext() { //Avoids going beyond the end of the collection. if (++curIndex >= _collection.Count) { return false; } else { // Set current box to next item in collection. curBox = _collection[curIndex]; } return true; } public void Reset() { curIndex = -1; } void IDisposable.Dispose() { } public Box Current { get { return curBox; } } object IEnumerator.Current { get { return Current; } } }
使用yield return
msdn 对yield的说明:在语句中使用 yield 关键字,表示在该关键字所在的方法、运算符或 get 访问器是迭代器。 通过使用 yield 定义迭代器,可在实现自定义集合类型的 IEnumerable 和 IEnumerator 模式时无需其他显式类。
public class BoxCollection { public IEnumerator<Box> GetEnumerator() { foreach (var i in innerCol) { yield return i; } }// The inner collection to store objects. private List<Box> innerCol; public BoxCollection() { innerCol = new List<Box>(); } // Adds an index to the collection. public Box this[int index] { get { return (Box)innerCol[index]; } set { innerCol[index] = value; } } // Determines if an item is in the collection // by using the BoxSameDimensions equality comparer. public bool Contains(Box item) { bool found = false; foreach (Box bx in innerCol) { // Equality defined by the Box // class's implmentation of IEquitable<T>. if (bx.Equals(item)) { found = true; } } return found; } public bool Contains(Box item, EqualityComparer<Box> comp) { bool found = false; foreach (Box bx in innerCol) { if (comp.Equals(bx, item)) { found = true; } } return found; } public void Add(Box item) { if (!Contains(item)) { innerCol.Add(item); } else { Console.WriteLine("A box with {0}x{1}x{2} dimensions was already added to the collection.", item.Height.ToString(), item.Length.ToString(), item.Width.ToString()); } } public void Clear() { innerCol.Clear(); } public void CopyTo(Box[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException("The array cannot be null."); if (arrayIndex < 0) throw new ArgumentOutOfRangeException("The starting array index cannot be negative."); if (Count > array.Length - arrayIndex + 1) throw new ArgumentException("The destination array has fewer elements than the collection."); for (int i = 0; i < innerCol.Count; i++) { array[i + arrayIndex] = innerCol[i]; } } public int Count { get { return innerCol.Count; } } public bool IsReadOnly { get { return false; } } }