web-dev-qa-db-ja.com

IEnumerable <T>を実装する方法

次のように、非ジェネリックIEnumerableを実装する方法を知っています。

using System;
using System.Collections;

namespace ConsoleApplication33
{
    class Program
    {
        static void Main(string[] args)
        {
            MyObjects myObjects = new MyObjects();
            myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 };
            myObjects[1] = new MyObject() { Foo = "World", Bar = 2 };

            foreach (MyObject x in myObjects)
            {
                Console.WriteLine(x.Foo);
                Console.WriteLine(x.Bar);
            }

            Console.ReadLine();
        }
    }

    class MyObject
    {
        public string Foo { get; set; }
        public int Bar { get; set; }
    }

    class MyObjects : IEnumerable
    {
        ArrayList mylist = new ArrayList();

        public MyObject this[int index]
        {
            get { return (MyObject)mylist[index]; }
            set { mylist.Insert(index, value); }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return mylist.GetEnumerator();
        }
    }
}

ただし、IEnumerableには汎用バージョンIEnumerable<T>があることにも気付きましたが、実装方法がわかりません。

using System.Collections.Generic;をusingディレクティブに追加してから変更した場合:

class MyObjects : IEnumerable

に:

class MyObjects : IEnumerable<MyObject>

そして、IEnumerable<MyObject>を右クリックしてImplement Interface => Implement Interfaceを選択すると、Visual Studioは次のコードブロックを追加してくれます。

IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
{
    throw new NotImplementedException();
}

GetEnumerator();メソッドから一般的でないIEnumerableオブジェクトを返すことは今回は機能しません。そこで、ここに何を入れますか? CLIは、foreachループ中に配列を列挙しようとすると、非汎用実装を無視し、汎用バージョンに直接向かいます。

113
JMK

ArrayListの代わりにList<MyObject>などの汎用コレクションを使用することを選択した場合、List<MyObject>が使用できる汎用および非汎用の両方の列挙子を提供することがわかります。

using System.Collections;

class MyObjects : IEnumerable<MyObject>
{
    List<MyObject> mylist = new List<MyObject>();

    public MyObject this[int index]  
    {  
        get { return mylist[index]; }  
        set { mylist.Insert(index, value); }  
    } 

    public IEnumerator<MyObject> GetEnumerator()
    {
        return mylist.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
137
Monroe Thomas

おそらく、explicitIEnumerable<T>の実装は望まないでしょう(これはあなたが示したものです)。

通常のパターンは、IEnumerableの明示的な実装でIEnumerable<T>のGetEnumeratorを使用することです。

class FooCollection : IEnumerable<Foo>, IEnumerable
{
    SomeCollection<Foo> foos;

    // Explicit for IEnumerable because weakly typed collections are Bad
    System.Collections.IEnumerator IEnumerable.GetEnumerator()
    {
        // uses the strongly typed IEnumerable<T> implementation
        return this.GetEnumerator();
    }

    // Normal implementation for IEnumerable<T>
    IEnumerator<Foo> GetEnumerator()
    {
        foreach (Foo foo in this.foos)
        {
            yield return foo;
            //nb: if SomeCollection is not strongly-typed use a cast:
            // yield return (Foo)foo;
            // Or better yet, switch to an internal collection which is
            // strongly-typed. Such as List<T> or T[], your choice.
        }

        // or, as pointed out: return this.foos.GetEnumerator();
    }
}
55
user7116

なぜ手動で行うのですか? yield return イテレータを処理するプロセス全体を自動化します。 (私はそれについても書いた 私のブログで 、コンパイラが生成したコードを見て)。

本当に自分でやりたい場合は、汎用の列挙子も返す必要があります。 ArrayListは一般的ではないため、これ以上使用することはできません。代わりにList<MyObject>に変更してください。もちろん、コレクションにはMyObject型(または派生型)のオブジェクトしかないことを前提としています。

24
Anders Abel

ジェネリックを扱う場合は、ArrayListの代わりにListを使用してください。リストには、必要なGetEnumeratorメソッドがあります。

List<MyObject> myList = new List<MyObject>();
4
Amiram Korach

mylistをList<MyObject>にする、1つのオプション

0
ColWhi