C#集合:枚举IEnumerable
IEnumerable 和 IEnumerator
IEnumerator
接口定义了以向前方式遍历集合的基本底层协议。
声明如下:
public interface IEnumerator
{
bool MoveNext();
object Current { get; }
void Reset();
}
MoveNext
将当前元素向前移动到下一个位置,如果集合没有更多元素,那么它会返回false。Current
返回当前位置元素。在取得第一个元素之前 必须先调用MoveNext
,即使空集合也支持该操作。Reset
作用就是当前位置移回起点,并允许再一次枚举集合。此方法一般并不建议使用,因为完全可以重新实例化一个枚举器。
通常,集合本身并不实现枚举器,而是通过IEnumerable
接口提供枚举器:
public interface IEnumerable:
{
IEnumerator GetEnumerator();
}
通过GetEnumerator
返回枚举器,可以灵活地将迭代逻辑转移到另一个类上。此外,多个消费者可以同时枚举同一个集合而不互相影响。IEnumerable
可以看作IEnumerator
的提供者,它是所有集合类需要实现的最基础接口。
下面示例了基本用法:
string s = "Hello";
IEnumerator rator = s.GetEnumerator();
while (rator.MoveNext())
{
char c = (char)rator.Current;
Console.Write(c + ".");
}
然而,我们很少采用这种方式直接调用枚举器的方法,因为C#提供了更快捷的语法:foreach
语句。
foreach (char c in s)
{
Console.Write(c + ".");
}
IEnumerable<T> 和 IEnumerator<T>
IEnumerable 和 IEnumerator 总是和它们的泛型版本同时实现:
public interface IEnumerator<T> : IEnumerator, IDisposable
{
T Current { get; }
}
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
这些接口通过定义一个类型化的Current
和GetEnumerator
强化了静态类型安全性,避免了值类型元素装箱的额外开销,更加方便了。
集合类的标准做法是公开提供IEnumerable<T>
接口,并通过显式接口实现,而“隐藏”非泛型的IEnumerable
接口。如果直接调用GetEnumerator()
,则返回类型安全的泛型IEnumerator<T>
。但是有时候这个规则也会由于向后兼容性而破坏,比如数组就必须返回非泛型的以避免破坏之前C#版本代码。
IEnumerator<T>
也同时继承了IDisposable
,这样枚举器就可以在枚举结束后确保释放这些资源。
本文来自博客园,作者:一纸年华,转载请注明原文链接:https://www.cnblogs.com/nullcodeworld/p/16424911.html