Ability to reset IEnumerator generated using yield (C#)

后端 未结 5 2135
情歌与酒
情歌与酒 2021-02-05 08:00

If I use yield instead of manually creating an IEnumerator, is it possible to implement IEnumerator.Reset?

5条回答
  •  半阙折子戏
    2021-02-05 08:47

    My solution to this problem is to use a Wrapper class that can wrap any yielding function and reset:

    public class Resettable : IEnumerator
    {
      private IEnumerator inner;
      private Func func;
    
      public Resettable(Func func)
      {
        this.func = func;
        inner = func.Invoke();
      }
    
      public bool MoveNext()
      {
        return inner.MoveNext();
      }
    
      public object Current { get { return inner.Current; } }
    
      public void Reset()
      {
        inner = func.Invoke();
      }
    
      public static Resettable Make(Func func)
      {
        return new Resettable(func);
      }
    
      public static Resettable Make(Func func, T1 a1)
      {
        Func capture = () => { return func.Invoke(a1); };
        return new Resettable(capture);
      }
    
      public static Resettable Make(Func func, T1 a1, T2 a2)
      {
        Func capture = () => { return func.Invoke(a1, a2); };
        return new Resettable(capture);
      }
    
      public static Resettable Make(Func func, T1 a1, T2 a2, T3 a3)
      {
        Func capture = () => { return func.Invoke(a1, a2, a3); };
        return new Resettable(capture);
      }
    
      // add more of these to support more arguments
    }
    

    then, instead of calling your yielding method directly, you call Resettable.Make(YourMethod, ..arguments..);

    so, here's an example usage:

    public class Program
    { 
      static IEnumerator YieldTest(int start)
      {
        yield return start;
        yield return start + 1;
        yield return start + 2;
      }
        
      public static void Main()
      {
        // IEnumerator en = YieldTest(5);
        IEnumerator en = Resettable.Make(YieldTest, 5);
    
        while(en.MoveNext())
        {
          Console.WriteLine("value: "+en.Current.ToString());
        }
        Console.WriteLine("Reset");
        en.Reset();
        while(en.MoveNext())
        {
          Console.WriteLine("value: "+en.Current.ToString());
        }
      }
    }
    

    Output:

    value: 5
    value: 6
    value: 7
    Reset
    value: 5
    value: 6
    value: 7
    

提交回复
热议问题