枚举集合
.NET Framework 提供枚举数作为循环访问一个集合的简单方法。 枚举数只读取集合中的数据,无法用于修改基础集合。
有些语言提供一个隐藏直接使用枚举数的复杂性的语句。 C# foreach 语句、C++ for each 语句和 Visual Basic For Each 语句使用枚举数。
关于枚举数
一个枚举数展平一个集合,以便可以按顺序访问成员。 不同的集合类可能具有不同的序列。 例如,ArrayList 的枚举数保留在集合中输入元素时的顺序,而 Hashtable 的枚举数根据元素的哈希代码显示元素。
每一枚举数都基于 IEnumerator 接口或 IEnumerator<T> 泛型接口,这两个接口要求以下成员:
Current 属性指向集合中的当前成员。
MoveNext 属性将枚举数移到集合中的下一成员。
Reset 属性将枚举数移回集合的开始处。 Current 被定位于第一个元素的前面。 Reset 在泛型 IEnumerator<T> 接口中不可用。
枚举数的行为
最初,枚举数被定位于集合中第一个元素的前面。 Reset 还将枚举数返回到此位置。 在此位置上,Current 为未定义。 因此,您必须调用 MoveNext,以在读取 Current 的值之前将该枚举数提前到该集合的第一个元素。
Current 返回相同的对象,直到调用 MoveNext 或 Reset 为止。 MoveNext 将 Current 设置为下一个元素。
如果 MoveNext 超过集合的末尾,枚举数将被定位在集合中最后一个元素之后,而且 MoveNext 返回 false。 枚举数处于这个位置时,随后对 MoveNext 的调用也会返回 false。 如果对 MoveNext 的最后一次调用返回 false,则 Current 为未定义。
在非泛型集合中,您可以在调用 Reset 后调用 MoveNext,将枚举数移回集合的开始处。
在泛型集合中,您不能再将 Current 设置为集合的第一个元素;而须创建新的枚举数实例。
只要集合保持不变,枚举数就保持有效。 如果对集合进行更改(如添加、修改或删除元素),则枚举数将失效且不可恢复,而且其行为是不确定的。
枚举数没有对集合的独占访问权;因此,从头到尾对一个集合进行枚举在本质上不是一个线程安全的过程。 若要确保枚举过程中的线程安全,可以在整个枚举过程中锁定集合。 若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步或使用 System.Collections.Concurrent 命名空间中的线程安全集合类之一。 System.Collections.Concurrent.ConcurrentQueue<T> 和 System.Collections.Concurrent.ConcurrentStack<T> 类在枚举元素之前将为元素拍摄快照,以防止转变成另一个线程上的集合。 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> 类不拍摄快照。
System.Collections.Concurrent.BlockingCollection<T> 类提供一个名为 GetConsumingEnumerable 的枚举器方法,该方法通过在枚举项时将项从集合中移除来转变集合。