当前位置: 首页 > news >正文

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

在面向对象编程中,迭代器模式是一种非常重要的行为型设计模式。它主要用于顺序访问集合对象中的元素,而无需暴露该集合的内部结构。在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 接口,我们可以轻松实现多种遍历方式,满足复杂业务需求。

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

http://www.lryc.cn/news/605902.html

相关文章:

  • 安装 docker compose v2版 笔记250731
  • docker离线安装mysql镜像
  • 内存网格、KV存储和Redis的概念、使用场景及异同
  • 分布式锁ZK与redis
  • Redis 存在哪些问题
  • 【问题】Docker 容器内的应用(如n8n),访问不到外部主机的应用(如mysql)
  • 【单片机】【分布式】从单机到分布式:Redis如何成为架构升级的关键力量
  • react调用接口渲染数据时,这些表格里的数据是被禁选的
  • 【Unity笔记04】数据持久化
  • TypeScript 基础介绍(二)
  • 雷霆战机游戏代码
  • ubuntu22.04系统入门 linux入门 简单命令基础复习 实现以及实践
  • Flask Bootstrap 后台权限管理方案
  • diffusion原理和代码延伸笔记1——扩散桥,GOUB,UniDB
  • 功能强大编辑器
  • PDF源码解析
  • QT Word模板 + QuaZIP + LibreOffice,跨平台方案实现导出.docx文件后再转为.pdf文件
  • WebSocket配置实战:打造稳健高效的消息通信系统
  • 学C笔记——更新于0731
  • 网络攻击新态势企业级安全防御指南
  • C# 枚举器和迭代器(常见迭代器模式)
  • 深入剖析:C++ 手写实现 unordered_map 与 unordered_set 全流程指南
  • 【React】fiber 架构
  • vue 中 props 直接解构的话会数据丢失响应式
  • MakeInstaller: 一款麒麟操作系统安装包制作工具
  • 3DXML 转换为 UG 的技术指南及迪威模型网在线转换推荐
  • DeepSeek笔记(三):结合Flask实现以WEB方式访问本地部署的DeepSeek-R1模型
  • 戴尔笔记本Ubuntu18.04 NVIDIA驱动与cuda环境配置教程
  • 【国内电子数据取证厂商龙信科技】内存取证
  • 工业绝缘监测仪:保障工业电气安全的关键防线