You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不使用yield语句实现Iterator模式(IEnumerator<T>)并手动重写GetEnumerator方法

Manual Implementation of IEnumerator<T> Without yield

Great question! When you use the yield keyword, C# secretly generates a state machine class behind the scenes to handle the enumeration flow. To replicate the behavior of your original method manually, we need to build that state machine ourselves by implementing IEnumerator<int> (and IDisposable, since it's required by the generic enumerator interface).

First, let's recap what your original yield method does:

  • The first call to MoveNext() returns true, and Current is set to 1.
  • After the caller retrieves that value, the next MoveNext() executes Console.WriteLine("1"), sets Current to 2, and returns true.
  • A third MoveNext() call returns false, ending the enumeration.

Step 1: Create the State Machine Class

We'll make a class that tracks the current state of the enumeration, handles transitions, and implements all required interface members:

public class NumberEnumerator : IEnumerator<int>, IDisposable
{
    // Tracks which part of the enumeration we're in
    private int _enumerationState;

    // Implements the Current property from IEnumerator<int>
    public int Current { get; private set; }

    // Explicit implementation of the non-generic IEnumerator.Current
    object IEnumerator.Current => Current;

    public bool MoveNext()
    {
        switch (_enumerationState)
        {
            // Initial state: return the first value
            case 0:
                Current = 1;
                _enumerationState = 1;
                return true;
            
            // After first yield: execute the console line, then return the second value
            case 1:
                Console.WriteLine("1");
                Current = 2;
                _enumerationState = 2;
                return true;
            
            // No more values to return
            case 2:
                return false;
            
            default:
                return false;
        }
    }

    // Reset the enumerator to its initial state (rarely used in practice)
    public void Reset()
    {
        _enumerationState = 0;
        Current = default;
    }

    // Dispose method (required by IDisposable; empty here since we have no unmanaged resources)
    public void Dispose()
    {
        // Cleanup logic would go here if we had resources to release
    }
}

Step 2: Rewrite the GetEnumerator Method

Now replace your original yield-based method with one that returns an instance of our manual state machine:

public IEnumerator<int> GetEnumerator()
{
    return new NumberEnumerator();
}

How This Matches the yield Version

This manual implementation behaves exactly like the original yield code. The C# compiler would generate nearly identical state machine logic when it encounters yield return—the only difference is we're writing it explicitly instead of letting the compiler handle it.

Note: In most real-world scenarios, using yield is preferable because it's cleaner and less error-prone. Manual state machines are mostly useful for understanding how enumerators work under the hood, or for rare cases where you need full control over the enumeration flow.

内容的提问来源于stack exchange,提问作者Jorge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:29:21