首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# IEnumerator 與 IEnumerable 實作指南:自訂枚舉器完整範例

     編輯:關於C#

核心介面定義


// 非泛型
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

public interface IEnumerator
{
    object Current { get; }
    bool MoveNext();
    void Reset();
}

// 泛型 (推薦)
public interface IEnumerable : IEnumerable
{
    IEnumerator GetEnumerator();
}

public interface IEnumerator : IDisposable, IEnumerator
{
    T Current { get; }
}

實作非泛型枚舉器:ColorEnumerator


using System;
using System.Collections;

public class ColorEnumerator : IEnumerator
{
    private readonly string[] _colors;
    private int _position = -1;

    public ColorEnumerator(string[] colors)
    {
        _colors = new string[colors.Length];
        Array.Copy(colors, _colors, colors.Length);
    }

    public object Current
    {
        get
        {
            if (_position == -1 || _position >= _colors.Length)
                throw new InvalidOperationException("枚舉器位於無效位置");
            return _colors[_position];
        }
    }

    public bool MoveNext()
    {
        if (_position < _colors.Length - 1)
        {
            _position++;
            return true;
        }
        return false;
    }

    public void Reset() => _position = -1;
}

可枚舉容器:ColorCollection


public class ColorCollection : IEnumerable
{
    private readonly string[] _colors;

    public ColorCollection(params string[] colors) => _colors = colors;

    public IEnumerator GetEnumerator() => new ColorEnumerator(_colors);
}

使用範例


var colors = new ColorCollection("Red", "Green", "Blue", "Yellow");

foreach (string color in colors)
    Console.WriteLine(color);

// 手動枚舉
var enumerator = colors.GetEnumerator();
while (enumerator.MoveNext())
    Console.WriteLine(enumerator.Current);

泛型版本 (現代標準)


public class GenericColorCollection : IEnumerable
{
    private readonly string[] _colors;
    public GenericColorCollection(params string[] colors) => _colors = colors;

    public IEnumerator GetEnumerator() => new GenericColorEnumerator(_colors);
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); // 非泛型介面顯式實作
}

public class GenericColorEnumerator : IEnumerator
{
    private readonly string[] _colors;
    private int _position = -1;

    public GenericColorEnumerator(string[] colors) => _colors = colors;

    public string Current => (_position >= 0 && _position < _colors.Length) ? _colors[_position] 
        : throw new InvalidOperationException();

    object IEnumerator.Current => Current;

    public bool MoveNext() => ++_position < _colors.Length;

    public void Reset() => _position = -1;

    public void Dispose() { } // 無非託管資源
}

yield return 自動實作 (C# 2.0+、最簡潔)


public class YieldColorCollection : IEnumerable
{
    private readonly string[] _colors;
    public YieldColorCollection(params string[] colors) => _colors = colors;

    public IEnumerator GetEnumerator()
    {
        foreach (var color in _colors)
            yield return color; // 編譯器自動產生狀態機類別
    }
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

進階:支援 Reset 的 yield 實作

yield return 產生的枚舉器不支援 Reset (呼叫會拋出 NotSupportedException),若需支援 Reset 必須手動實作 IEnumerator。

關鍵差異對比

特性手動實作 IEnumeratoryield return
程式碼量多極少
Reset 支援可控制不支援
狀態管理手動編譯器自動產生狀態機
效能略優 (無狀態機開銷)極佳 (編譯器優化)
除錯容易設中斷點較難 (狀態機)
適用場景需精確控制、支援 Reset、教學99% 一般情況

實作檢查清單

  1. 實作 IEnumerable<T> (含非泛型 IEnumerable 顯式實作)
  2. 實作 IEnumerator<T> : IDisposable, IEnumerator
  3. Current 正確處理邊界 (-1、超出長度)
  4. MoveNext 正確推進並回傳是否有下一項
  5. Reset 重置至初始狀態 (-1)
  6. Dispose 釋放資源 (若有)
  7. 類別不可變 (傳入陣列需防禦性複製)

常見錯誤

  • 忘記實作非泛型 IEnumerable.GetEnumerator() → 編譯錯誤
  • Current 未檢查邊界 → IndexOutOfRangeException
  • MoveNext 邏輯錯誤導致漏項或重複
  • 直接回傳外部陣列參考 → 封裝性破壞
  • 在 foreach 中修改集合 → InvalidOperationException (需自行處理)

掌握 IEnumerable/IEnumerator 實作,是理解 C# 迭代器模式、LINQ 底層運作與自訂集合的基礎。現代開發首選 yield return,特殊需求再手動實作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved