手记

深入理解 C#.NET IEnumerable<T>:一切集合的起点

IEnumerable<T> 是 .NET 中最核心的接口之一,位于 System.Collections.Generic 命名空间中。它代表一个可枚举的集合,支持在集合上进行迭代操作。

IEnumerable<T> 是什么?

public interface IEnumerable<out T> : IEnumerable{    IEnumerator<T> GetEnumerator();
}
  • 它定义了一个可枚举对象的契约;

  • 任何实现了 IEnumerable<T> 的类型都能被 foreach 循环遍历;

  • 泛型版 IEnumerable<T> 是非泛型 IEnumerable 的类型安全扩展;

  • 它的核心方法只有一个:GetEnumerator()

IEnumerable 与 IEnumerator 的关系

要理解 IEnumerable<T>,必须知道它依赖另一个接口:

public interface IEnumerator<out T> : IDisposable, IEnumerator{
    T Current { get; }    bool MoveNext();    void Reset(); // 通常不实现}

关系示意图:

IEnumerable<T>
    └── GetEnumerator()
          └── 返回 IEnumerator<T>
                  ├── MoveNext() → 是否还有元素
                  ├── Current → 当前元素
                  └── Reset() → 重置(可选)

基本用法

using System;using System.Collections.Generic;class Program{    static void Main()
    {
        List<string> fruits = new List<string> { "Apple", "Banana", "Cherry" };        
        // 使用 foreach 遍历(推荐)
        foreach (string fruit in fruits)
        {
            Console.WriteLine(fruit);
        }        
        // 等价的手动迭代方式
        IEnumerator<string> enumerator = fruits.GetEnumerator();        try
        {            while (enumerator.MoveNext())
            {                string fruit = enumerator.Current;
                Console.WriteLine(fruit);
            }
        }        finally
        {
            enumerator?.Dispose();
        }
    }
}

手写一个 IEnumerable<T> 示例

public class NumberCollection : IEnumerable<int>
{    private readonly int[] _numbers = { 1, 2, 3, 4, 5 };    public IEnumerator<int> GetEnumerator()
    {        foreach (var n in _numbers)            yield return n;
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

使用:

var numbers = new NumberCollection();foreach (var n in numbers)
{
    Console.WriteLine(n);
}

输出:

1
2
3
4
5

yield return 的魔法

等价于下面的展开版:

public IEnumerator<int> GetEnumerator(){    return new Enumerator();
}private class Enumerator : IEnumerator<int>
{    private int _index = -1;    private readonly int[] _numbers = { 1, 2, 3, 4, 5 };    public int Current => _numbers[_index];    object IEnumerator.Current => Current;    public bool MoveNext()
    {
        _index++;        return _index < _numbers.Length;
    }    public void Reset() => _index = -1;    public void Dispose() { }
}

yield 编译后自动生成状态机类,就是这种效果。


0人推荐
随时随地看视频
慕课网APP