一、概念

C#迭代器(Iterator)是一种特殊类型的方法,它使得在使用循环遍历数据集合时更加简单和有效。使用迭代器可以通过简单地定义迭代器方法来自动实现枚举器模式。

当您需要访问一个数据集合中的每个元素时,可以使用迭代器来遍历该集合。C#中的迭代器通过yield关键字实现。yield语句用于指示方法返回一个序列,并返回一系列值。这些值会被逐个返回到调用方,并且方法的当前状态会保留下来,以便下次调用时继续执行。

以下是一个使用迭代器的简单示例,其中展示了如何使用它来遍历整数数组:

```csharp
static IEnumerable<int> GetNumbers()
{
int[] numbers = { 1, 2, 3, 4, 5 };
foreach (int number in numbers)
{
yield return number;
}
}
```

在这个示例中,GetNumbers()方法返回一个IEnumerable<int>类型的迭代器。在foreach循环中,使用yield return语句依次返回数组中的每个数字。

使用迭代器有以下几个好处:

1. 简化代码结构:使用迭代器使得代码结构更加清晰、简洁。

2. 节省内存:由于迭代器只是逐个返回序列中的元素,所以可以大大减少内存的使用。

3. 延迟计算:当使用yield return语句时,元素是按需生成的,这意味着在需要时才会计算。这可以提高性能,并允许处理非常大的数据集合。

4. 支持Linq查询:由于迭代器实现了IEnumerable和IEnumerator接口,因此它们可以与Linq查询一起使用。

总之,C#迭代器是一种非常有用的工具,它使得遍历和操作数据集合变得更加简单、高效和灵活。通过使用yield关键字,可以轻松地定义自己的迭代器方法,并利用其强大的功能来提高代码质量和性能。

二、使用场景

以下是使用C#迭代器的经典场景和演示代码:

  1. 遍历集合数据

使用 C# 迭代器可以更方便地遍历一个集合中的所有元素,而不必事先知道集合的大小。

public class MyList<T> : IEnumerable<T>
{
private List<T> _list; public MyList()
{
_list = new List<T>();
} public void Add(T item)
{
_list.Add(item);
} public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _list.Count; i++)
{
yield return _list[i];
}
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} // 使用 MyList 遍历元素
var list = new MyList<int>();
list.Add(1);
list.Add(2);
list.Add(3); foreach (var item in list)
{
Console.WriteLine(item);
} 输出结果:
1
2
3
  1. 实现延迟加载

使用 C# 迭代器可以实现延迟加载,也就是说只有在需要访问某个元素时才会去加载它,从而提高程序的性能和效率。

public class LazyDataLoader<T> : IEnumerable<T>
{
private Func<IEnumerable<T>> _dataLoader; public LazyDataLoader(Func<IEnumerable<T>> dataLoader)
{
_dataLoader = dataLoader;
} public IEnumerator<T> GetEnumerator()
{
foreach (var item in _dataLoader())
{
yield return item;
}
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} // 使用 LazyDataLoader 延迟加载数据
var dataLoader = new LazyDataLoader<int>(() => Enumerable.Range(1, 100000)); foreach (var item in dataLoader)
{
Console.WriteLine(item);
} 输出结果:
1
2
...
99999
100000
  1. 处理大型数据集

如果数据集非常大,无法一次性全部加载到内存中,使用 C# 迭代器可以分批次地读取数据,从而降低内存消耗。

public class BigDataLoader<T> : IEnumerable<T>
{
private Func<IEnumerable<T>> _dataLoader;
private int _batchSize; public BigDataLoader(Func<IEnumerable<T>> dataLoader, int batchSize)
{
_dataLoader = dataLoader;
_batchSize = batchSize;
} public IEnumerator<T> GetEnumerator()
{
var buffer = new T[_batchSize];
var count = 0; foreach (var item in _dataLoader())
{
buffer[count++] = item; if (count == _batchSize)
{
for (int i = 0; i < count; i++)
{
yield return buffer[i];
} count = 0;
}
} for (int i = 0; i < count; i++)
{
yield return buffer[i];
}
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} // 使用 BigDataLoader 分批次读取数据
var bigDataLoader = new BigDataLoader<int>(() => Enumerable.Range(1, 100000), 1000); foreach (var item in bigDataLoader)
{
Console.WriteLine(item);
}
输出结果:
1
2
...
99999
100000
  1. 实现自定义的遍历逻辑

有时候我们需要按照特定的顺序或方式遍历集合数据,使用 C# 迭代器可以方便地实现自定义的遍历逻辑。

public class EvenNumberGenerator : IEnumerable<int>
{
private int _start;
private int _end; public EvenNumberGenerator(int start, int end)
{
_start = start % 2 == 0 ? start : start + 1;
_end = end % 2 == 0 ? end : end - 1;
} public IEnumerator<int> GetEnumerator()
{
for (int i = _start; i <= _end; i += 2)
{
yield return i;
}
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} // 使用 EvenNumberGenerator 遍历偶数
var evenNumbers = new EvenNumberGenerator(10, 20); foreach (var item in evenNumbers)
{
Console.WriteLine(item);
}
输出结果:
10
12
14
16
18
20
  1. 简化代码结构

使用 C# 迭代器可以简化代码结构,使得代码更加易读易懂,从而提高代码的可维护性和可读性。

public class FibonacciSequence : IEnumerable<int>
{
private int _count; public FibonacciSequence(int count)
{
_count = count;
} public IEnumerator<int> GetEnumerator()
{
int a = 0;
int b = 1; for (int i = 0; i < _count; i++)
{
yield return a; int temp = a;
a = b;
b = temp + b;
}
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} // 使用 FibonacciSequence 生成斐波那契数列
var fibonacci = new FibonacciSequence(10); foreach (var item in fibonacci)
{
Console.WriteLine(item);
} 输出结果:
0
1
1
2
3
5
8
13
21
34

《c#高级编程》第2章C#2.0中的更改(三)——迭代器的更多相关文章

  1. javascript高级编程3第二章:在html中使用javascript

    2.1 <script>元素 向html页面中插入javascript的主要方法,就是使用<script>元素.这个元素被加入到正式的html规范中.html4.01为< ...

  2. ASP.NET MVC5 高级编程 第5章 表单和HTML辅助方法

    参考资料<ASP.NET MVC5 高级编程>第5版 第5章 表单和HTML辅助方法 5.1 表单的使用 5.1.1 action 和 method 特性 默认情况下,表单发送的是 HTT ...

  3. ASP.NET MVC5 高级编程 第3章 视图

    参考资料<ASP.NET MVC5 高级编程>第5版 第3章 视图 3.1 视图的作用 视图的职责是向用户提供界面. 不像基于文件的框架,ASP.NET Web Forms 和PHP ,视 ...

  4. ASP.NET MVC5 高级编程 第2章 控制器

    参考资料<ASP.NET MVC5 高级编程>第5版 第2章 控制器 控制器:响应用户的HTTP 请求,并将处理的信息返回给浏览器. 2.1 ASP.NET MVC 简介 MVC 模式中的 ...

  5. UNIX环境高级编程 第8章 进程控制

    本章是UNIX系统中进程控制原语,包括进程创建.执行新程序.进程终止,另外还会对进程的属性加以说明,包括进程ID.实际/有效用户ID. 进程标识 每个进程某一时刻在系统中都是独一无二的,它们之间是用一 ...

  6. 【读书笔记】C#高级编程 第五章 泛型

    (一)泛型概述 泛型不仅是C#编程语言的一部分,而且与程序集中的IL代码紧密地集成.泛型不仅是C#语言的一种结构,而且是CLR定义的.有了泛型就可以创建独立于被包含类型的类和方法了. 1.性能 泛型的 ...

  7. 第四章 在MVC4.0中对脚本以及样式表的引用变化

    原文:http://www.cnblogs.com/xdotnet/archive/2012/07/21/aspnet40_webpage20.html 一.可以直接使用“~”,而无需使用Href对象 ...

  8. C#高级编程第1章-.NET体系结构

    内容提要: (1)编译和运行面向对象.NET代码 (2)IL/MSIL(Microsoft Intermediate Language)中间语言的优点 (3)值类型与引用类型 (4)数据类型化 (5) ...

  9. C#高级编程第2章-核心C#

    内容提要: 声明变量:变量的初始化和作用域:C#的预定义数据类型:在C#程序中使用条件语句.循环和跳转语句指定执行流:枚举:名称空间: Main()方法:基本命令行C#编译器选项:使用System.C ...

  10. UNIX环境高级编程 第13章 守护进程

    守护进程daemon是一种生存周期很长的进程.它们通常在系统引导时启动,在系统关闭时终止.守护进程是没有终端的,它们一直在后台运行. 守护进程的特征 在Linux系统中,可以通过命令 ps -efj ...

随机推荐

  1. obs 录制教程 手机录屏用 向日葵 手机投屏 能用有线用有线的连接

    obs 录制教程 手机录屏用 向日葵 手机投屏 稍微有点卡 华为手机有个投屏 笔记本不支持这个 miracast 淘宝有卖 投屏设备的,搜 miracast 100多米 免费的就用向日葵就得了. 最新 ...

  2. 在Linux平台使用wps卡顿现象解决方法

    是因为软件占据的内存过多,需要关掉目前不使用的软件,以释放系统内存.

  3. Kotlin 语法糖(对象不为空返回自身,为空返回其他)

    原文地址: Kotlin 语法糖(对象不为空返回自身,为空返回其他) - Stars-One的杂货小窝 开发中,经常会有这样逻辑: 判断对象如果不为空,则取对象本身; 为空,则得到其他对象; 然后每次 ...

  4. day02-功能实现02

    功能实现02 6.功能05-显示家居信息 6.1需求分析 进入后台系统,可以在页面进行所有家居信息的展示 6.2思路分析 完成从后端代码从mapper(dao层)-->Service层--> ...

  5. new vs malloc

    https://www.cnblogs.com/qg-whz/p/5140930.html 1.申请内存位置 new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函 ...

  6. PAT 甲级1005【1005 Spell It Right】

    用JAVA可以用BigInteger解决. import java.io.BufferedReader; import java.io.IOException; import java.io.Inpu ...

  7. 06.Android之消息机制问题

    目录介绍 6.0.0.1 谈谈消息机制Hander作用?有哪些要素?流程是怎样的? 6.0.0.2 为什么一个线程只有一个Looper.只有一个MessageQueue,可以有多个Handler? 6 ...

  8. 探讨三维模型OBJ格式轻量化在数据存储的重要性

    探讨三维模型OBJ格式轻量化在数据存储的重要性 三维模型的OBJ格式轻量化在数据存储方面具有重要性.以下是对三维模型OBJ格式轻量化在数据存储的重要性进行浅析: 1.节省存储空间:原始的三维模型文件往 ...

  9. 2024-03-20:用go语言,自 01背包问世之后,小 A 对此深感兴趣。 一天,小 A 去远游,却发现他的背包不同于 01 背包,他的物品大致可分为 k 组。 每组中的物品只能选择1件,现在他想

    2024-03-20:用go语言,自 01背包问世之后,小 A 对此深感兴趣. 一天,小 A 去远游,却发现他的背包不同于 01 背包,他的物品大致可分为 k 组. 每组中的物品只能选择1件,现在他想 ...

  10. 创建远程仓库&克隆项目(Github)

    创建远程仓库 在GitHub上注册一个账号,之后creat a new repository 创建的远程仓库把它看作一个百度网盘就可以了 克隆项目 1.远程仓库可以下载\克隆到本地 code :git ...