枚举集合

.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 返回相同的对象,直到调用 MoveNextReset 为止。 MoveNextCurrent 设置为下一个元素。

如果 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 的枚举器方法,该方法通过在枚举项时将项从集合中移除来转变集合。

请参见

参考

IEnumerator

IEnumerator<T>

IDictionaryEnumerator

IEnumerable

IEnumerable<T>

概念

创建和操作集合

线程安全集合