hakeの日記

Windows環境でプログラミングの勉強をしています。

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です