【C#设计模式】深入理解常见迭代器模式(Iterator Pattern)

发布于:2025-08-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

在面向对象编程中,迭代器模式是一种非常重要的行为型设计模式。它主要用于顺序访问集合对象中的元素,而无需暴露该集合的内部结构。在C#中,迭代器模式通过 IEnumerableIEnumerator 接口实现,是实现 foreach 循环的基础。

本文将深入讲解常见的迭代器模式,包括如何创建可枚举类型、如何在类中实现多个迭代器方法,以及它们在实际开发中的应用方式。

迭代器模式的基本概念

什么是迭代器模式?

迭代器模式(Iterator Pattern)提供了一种访问聚合对象(如集合)元素的方式,而不暴露其内部结构。它将遍历逻辑封装在迭代器对象中,使得客户端代码可以一致地访问不同类型的聚合对象。

在 C# 中,迭代器的核心接口是:

  • IEnumerable:表示一个可枚举的集合,提供 GetEnumerator() 方法。
  • IEnumerator:表示集合的枚举器,提供 MoveNext()Reset()Current 方法。

C# 中的迭代器实现方式

在 C# 中,迭代器可以通过两种方式实现:

**方法一:**返回 IEnumerator 的迭代器

public IEnumerator<string> GetEnumerator()
{
    for (int i = 0; i < colors.Length; i++)
        yield return colors[i];
}

这种方式适用于类本身是可枚举类型(即实现了 IEnumerable 接口),并返回一个 IEnumerator

**方法二:**返回 IEnumerable 的迭代器

public IEnumerable<string> UVtoIR()
{
    for (int i = 0; i < colors.Length; i++)
        yield return colors[i];
}

这种方式返回一个可枚举对象,但类本身不一定是可枚举的,客户端可通过调用该方法来获取迭代器。

图解常见迭代器模式的使用方式

以下图示来源于《C# 图解教程》第19章图19-11,展示了两种常见的迭代器使用方式。

常见迭代器模式

类实现 GetEnumerator 成为可枚举类型

当一个类实现了 IEnumerable<T> 接口并重写了 GetEnumerator() 方法后,它就成为一个可枚举类型,可以被 foreach 遍历。

public class MyCollection : IEnumerable<string>
{
    private string[] items = { "A", "B", "C" };
 
    public IEnumerator<string> GetEnumerator()
    {
        return ((IEnumerable<string>)items).GetEnumerator();
    }
 
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

类不实现 GetEnumerator,但提供多个可枚举方法

有时我们希望一个类具备多个遍历方式(如正序、逆序、筛选等),但又不希望类本身是可枚举的。这时我们可以通过定义多个返回 IEnumerable<T> 的方法来实现。

public class Spectrum
{
    private string[] colors = { "violet", "blue", "cyan", "green", "yellow", "orange", "red" };
 
    public IEnumerable<string> UVtoIR()
    {
        for (int i = 0; i < colors.Length; i++)
            yield return colors[i];
    }
 
    public IEnumerable<string> IRtoUV()
    {
        for (int i = colors.Length - 1; i >= 0; i--)
            yield return colors[i];
    }
}

调用方式如下:

Spectrum spectrum = new Spectrum();
 
Console.WriteLine("UV to IR:");
foreach (string color in spectrum.UVtoIR())
{
    Console.WriteLine(color);
}
 
Console.WriteLine("IR to UV:");
foreach (string color in spectrum.IRtoUV())
{
    Console.WriteLine(color);
}

这种方式非常适合实现多维遍历逻辑,例如:按时间顺序、按优先级、按区域等。

迭代器模式的优势与应用场景

优势分析

优势 描述
封装性好 遍历逻辑与集合实现分离,降低耦合
扩展性强 可轻松添加新的遍历方式,如逆序、条件筛选等
支持延迟执行 使用 yield return 实现按需加载,节省资源
简化客户端代码 客户端只需使用 foreach,无需关心内部结构

典型应用场景

  • 数据集遍历:数据库查询结果、文件内容读取、网络数据流。
  • 多维遍历需求:如顺序、逆序、按条件过滤、分页等。
  • UI 控件绑定:WinForm、WPF、Blazor 中的数据绑定。
  • LINQ 查询实现:LINQ 中的 WhereSelect 等方法都依赖迭代器模式。

使用技巧与注意事项

使用 yield return 简化迭代器实现

C# 提供了 yield return 语法糖,可以非常方便地生成迭代器,而不需要手动实现 IEnumerator 接口。

public IEnumerable<int> GetEvenNumbers()
{
    for (int i = 0; i < 100; i++)
        if (i % 2 == 0)
            yield return i;
}

注意线程安全与状态同步

迭代器在执行过程中会保存当前状态,如果在多线程环境中使用,需要注意同步问题。

避免在迭代器中修改集合结构

在迭代过程中修改集合结构(如增删元素)会导致异常,应避免此类操作。

总结

迭代器模式是 C# 编程中非常常见且实用的设计模式。它不仅简化了集合的遍历操作,还提升了代码的可维护性和可扩展性。通过灵活使用 IEnumerableIEnumerator 接口,我们可以轻松实现多种遍历方式,满足复杂业务需求。

如果你正在开发一个需要支持多种遍历逻辑的类,或者希望提高代码的封装性和可复用性,迭代器模式绝对是一个非常值得掌握的设计模式。