1. 不是必须要IEnumerable和IEnumerator
众所周知foreach中in后面的对象应该是继承IEnumerable,程序运行时本质是在调用IEnumerable的GetEnumerator函数来返回一个IEnumerator对象,foreach就是利用IEnumerator对象的Current,MoveNext和Reset成员来进行一段数据的枚举,但是这个不是必须,比如下面代码:
class FakeIEnumerable { public FakeIEnumerator GetEnumerator() { return new FakeIEnumerator(new double[] { 1, 34.3, -43, Double.NaN, 0.0043}); } }
class FakeIEnumerator { double[] strs; int curIdx = -1;
public FakeIEnumerator(double[] data) { strs = data; }
public double Current { get { if (curIdx < 0 || curIdx >= strs.Length) throw new InvalidOperationException(); return strs[curIdx]; } }
public bool MoveNext() { return ++curIdx < strs.Length; }
public void Reset() { curIdx = -1; } }
class Program { static void Main() { foreach (var item in new FakeIEnumerable()) Console.WriteLine("类型: {0} 值: {1}", item.GetType(), item.ToString());
} } |
上面的两个类FakeIEnumerable和FakeIEnumerator都没有继承IEnumerable和IEnumerator,但是拥有IEnumerable和IEnumerator同名的成员信息,代码编译通过并成功运行。
输出
类型: System.Double 值: 1 类型: System.Double 值: 34.3 类型: System.Double 值: -43 类型: System.Double 值: NaN 类型: System.Double 值: 0.0043 |
可为什么这样呢?可以参考这个问题下面的回答,讲的不能再好了:
http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/64f3dbe3-5a1a-4a70-904a-792e26376dad
2. 支持继承IDisposable的IEnumerator
继承IDisposable的迭代器在foreach结束后会被正确处理掉(调用Dispose方法),另外这个不仅针对真的迭代器(继承IEnumerator的类),连上面说到的那个伪迭代器类FakeIEnumerator都是同等对待的。
更改上面FakeIEnumerator类代码
class FakeIEnumerator: IDisposable { void IDisposable.Dispose() { Console.WriteLine("调用Dispose"); }
/* 后面代码同上... */ } |
运行结果
类型: System.Double 值: 1 类型: System.Double 值: 34.3 类型: System.Double 值: -43 类型: System.Double 值: NaN 类型: System.Double 值: 0.0043 调用Dispose |