UnityVisualNovel (16-3) を進める をおこなううで、 csharp の IEnumerator と IEnumerable がわからなかったので調べます。

IEnumerable

public interface IEnumerable<out T> : IEnumerable
{
  IEnumerator<T> GetEnumerator();
}

IEnumerator を公開するだけのインターフェースです。

foreach は IEnumerable を受け取ることができます。 これは糖衣構文であり、 foreach は IEnumerable から IEnumerator を取り出して MoveNext で要素を取得しています。

IEnumerator

https://qiita.com/dj_kusuha/items/2048391d821cb94fa489 https://kakovail.info/entry/advent_2023_cs#google_vignette

IEnumerator は System.Collections namespace で定義されているインターフェースです。 列挙子に関するインターフェースであり、順番にものを取得する、ときに使えます。

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

while に IEnumerator.MoveNext() を与えることでイテレータを順番に回す、が行えます。

サンプルとして下記を実装してみました。

List<T> は IEnumerable を実装しているため GetEnumerator で IEnumerator を返せます。 ここで、受け取り方として 3 つサンプル実装しています。 珍しいのが List<T>.Enumerator であり、これは partial struct です。 効率がよいようです。

MoveNext(), Current で反復処理を行えます。

            List<string> alphabets = new List<string> { "a", "b", "c" };
            // List<string> は IEnumerable を実装している
            // そのため GetEnumerator() で IEnumerator が得られる
 
            // List<T>.Enumerator は List<T> 配下で partial struct として定義されている構造体
            // そのまま IEnumeator として呼び出すよりも効率よくなっている
            List<string>.Enumerator enumerator = alphabets.GetEnumerator();
            
            // IEnumerator としても受け取れる
            IEnumerator enumerator2 = alphabets.GetEnumerator();
            // IEnumerator<T> としても受け取れる
            IEnumerator<string> enumerator3 = alphabets.GetEnumerator();
 
            // IEnumerator で Move
            while (enumerator.MoveNext())
            {
                enumerator.Current;
            }
 
        public partial struct Enumerator : System.Collections.Generic.IEnumerator<T>, System.Collections.IEnumerator, System.IDisposable
        {
            private object _dummy;
            public T Current { get { throw null; } }
            object System.Collections.IEnumerator.Current { get { throw null; } }
            public void Dispose() { }
            public bool MoveNext() { throw null; }
            void System.Collections.IEnumerator.Reset() { }
        }