IEnumerable
IEnumerable是C#中集合操作的核心接口之一,全程Interface Enumerable,表示可被枚举的集合的接口,定义了一个最简单的能力:可以用foreach来逐个访问元素。
用途
- foreach遍历 :只要对象可以被枚举,就可以用
foreach遍历(数组、列表、字典、数据库结果集等)。 - LINQ查询 :LINQ依赖于
IEnumerable<T>,查询是延迟执行的,只有foreach遍历时才会真正计算结果。 - 用于惰性(延迟)加载/流式数据 :
yield return。一般用于读取大文件逐行处理、数据库分页查询、网络流式传输、避免一次性加载全部数据进入内存等情况。 - 用于返回可枚举结果而不是具体的集合
如果希望立刻执行查询不延迟,或者想缓存结果防止多次计算的话,需要调用
ToList()/ToArray()转为具体的集合
使用场景
| 使用场景 | 是否适合用 IEnumerable | 原因 |
|---|---|---|
| 遍历集合 | ✅ | foreach 基于它 |
| 惰性执行(LINQ) | ✅ | Where/Select/Take 等都返回它 |
| 返回数据序列(流式) | ✅ | 可一边生成一边使用 |
| 小集合、需随机访问 | ❌ | 用 List 更方便 |
| 频繁访问、修改 | ❌ | IEnumerable只读、单向 |
IEnumerable和IEnumerator
IEnumerable只提供一个方法IEnumerator GetEnumerator(),是集合的外壳,用来创建迭代器IEnumerator是枚举器,用来逐个获取元素,是迭代的工具,用来控制如何遍历
csharp
public interface IEnumerable
{
IEnumerator GetEnumerator(); // 提供"迭代器"
}
// 泛型版本
public interface IEnumerable<T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
public interface IEnumerator
{
bool MoveNext(); // 翻到下一项
object Current { get; } // 当前项
void Reset(); // 回到起点(一般不用)
}
因手写 IEnumerator 太繁琐,C# 提供了语法糖,这个语法糖会让编译器自动生成 IEnumerator 实现。
csharp
public IEnumerable<int> MyRange(int start, int count)
{
for (int i = start; i < start + count; i++)
{
yield return i; // 自动生成 Enumerator
}
}
总结
| 特性 | 说明 |
|---|---|
| 接口定义 | IEnumerable<T>是一个能被遍历的集合接口 |
| 核心方法 | GetEnumerator() |
| 常见来源 | List、Array、LINQ 查询、yield 方法 |
| 是否延迟执行 | 取决于实现(List否,LINQ 查询 是) |
| 优点 | 通用、节省内存、可惰性执行、可扩展 |
| 缺点 | 不支持随机访问、只读、无法修改集合内容 |