C# - foreach文とIEnumerableインターフェース(ジェネリック)
ジェネリックに対応させるには、昨日に対してIEnumerable<T>、IEnumerator<T>とIDisposableインターフェースを追加して継承する。
interface IEnumerable<T> { IEnumerator<T> GetEnumerator(); } interface IEnumerator<T> { T Current { get; } }
GetEnumeratorメソッドはIEnumerator<T>型オブジェクトを、CurrentプロパティはT型を戻り値とするため、追加の定義を行う。IEnumerator内でファイルオープン等を行う場合は、IDisposable.Disposeメソッドで破棄の処理を記述する。
using System; using System.Collections; using System.Collections.Generic; //IEnumerableとIEnumerator(ジェネリック) //IEnumerable<T>は、IEnumerator<T> GetEnumerator()メソッドを持つ //IEnumerator<T>は、T Current プロパティ(get)を持つ //IEnumerable は、IEnumerator GetEnumerator()メソッドを持つ //IEnumerator は、以下を持つ // object Currentプロパティ(get) // void Reset()メソッド // bool MoveNext()メソッド //IDisposable は、void Dispose()メソッドを持つ class MyEnumerator<T> : IDisposable, IEnumerator<T>, IEnumerable<T>, IEnumerator, IEnumerable { private List<T> data; private int index = -1; public MyEnumerator(List<T> arg){ this.data = arg; } public T Current { get { Console.WriteLine("Current値( {0} )が読みだされました", this.data[this.index]); return this.data[this.index]; } } object IEnumerator.Current { get { Console.WriteLine("IEnumerator.Current(get)が実行されました"); Console.WriteLine("Current値( {0} )が読みだされました", this.data[this.index]); return this.data[this.index]; } } public void Reset() { Console.WriteLine("Reset()が実行されました"); this.index = -1; } public bool MoveNext() { Console.WriteLine("MeveNext()が実行されました"); this.index++; if(this.index >= this.data.Count) { Console.WriteLine("戻り値はFalseです"); return false; } else { Console.WriteLine("戻り値はTrueです"); return true; } } public IEnumerator<T> GetEnumerator() { Console.WriteLine("\nGetEnumerator()が実行されました"); this.Reset(); return this; } IEnumerator IEnumerable.GetEnumerator() { Console.WriteLine("\nIEnumerable.GetEnumerator()が実行されました"); this.Reset(); return this; } void IDisposable.Dispose() { } } class MyMain { public static void Main(string[] args) { MyEnumerator<int> me = new MyEnumerator<int>( new List<int>(){10,20,30} ); foreach(var e in me) { Console.WriteLine("foreach内: {0}", e ); } List<string> s = new List<string>(){"one", "two", "three"}; MyEnumerator<string> me2 = new MyEnumerator<string>( s ); foreach(var e in me2) { Console.WriteLine("foreach内: {0}", e ); } } }
実行結果
GetEnumerator()が実行されました Reset()が実行されました MeveNext()が実行されました 戻り値はTrueです Current値( 10 )が読みだされました foreach内: 10 MeveNext()が実行されました 戻り値はTrueです Current値( 20 )が読みだされました foreach内: 20 MeveNext()が実行されました 戻り値はTrueです Current値( 30 )が読みだされました foreach内: 30 MeveNext()が実行されました 戻り値はFalseです GetEnumerator()が実行されました Reset()が実行されました MeveNext()が実行されました 戻り値はTrueです Current値( one )が読みだされました foreach内: one MeveNext()が実行されました 戻り値はTrueです Current値( two )が読みだされました foreach内: two MeveNext()が実行されました 戻り値はTrueです Current値( three )が読みだされました foreach内: three MeveNext()が実行されました 戻り値はFalseです
参考
- https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.ienumerable-1
- https://docs.microsoft.com/ja-jp/dotnet/api/system.collections.generic.ienumerator-1
- IDisposable Interface (System) | Microsoft Docs
- IEnumerable Interface (System.Collections) | Microsoft Docs
- IEnumerator Interface (System.Collections) | Microsoft Docs