Ability to reset IEnumerator generated using yield (C#)

后端 未结 5 2010
情歌与酒
情歌与酒 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

    There is no built-in support, but you can define your own implementation of IEnumerator that delegates all method calls to the enumerator generated by C# and only lets you define your own behavior for the Reset method.

    The simplest version of the class would look like this:

    class ResetableEnumerator : IEnumerator
    {
      public IEnumerator Enumerator { get; set; }
      public Func> ResetFunc { get; set; }
    
      public T Current { get { return Enumerator.Current; } }
      public void  Dispose() { Enumerator.Dispose(); }
      object IEnumerator.Current { get { return Current; } }
      public bool  MoveNext() { return Enumerator.MoveNext(); }
      public void  Reset() { Enumerator = ResetFunc(); }
    }
    

    In this case, the ResetFunc that you specify returns a new IEnumerator, so your provided implementation of ResetFunc can do some cleanup or whatever you need to do when resetting and then return a new enumerator.

    IEnumerator Foo() { /* using yield return */ }
    IEnumerator PublicFoo() {
      return new ResetableEnumerator { 
        Enumerator = Foo(),
        ResetFunc = () => { 
          Cleanup();
          return Foo(); } };
    }
    

    You'll need to store all the originally local variables of the Foo method as fields of the class, so that you can access them in Cleanup (Note that the rest of the Foo body will never be executed after calling Reset), but that's still easier than writing a handwritten iterator!

提交回复
热议问题