web-dev-qa-db-fra.com

Comment implémenter IEnumerable <T>

Je sais comment implémenter le IEnumerable non générique, comme ceci:

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();
        }
    }
}

Cependant, j'ai aussi remarqué que IEnumerable a une version générique, IEnumerable<T>, mais je ne sais pas comment l'implémenter.

Si j'ajoute using System.Collections.Generic; à mes directives using, puis modifie:

class MyObjects : IEnumerable

à:

class MyObjects : IEnumerable<MyObject>

Cliquez ensuite avec le bouton droit de la souris sur IEnumerable<MyObject> et sélectionnez Implement Interface => Implement Interface. Visual Studio ajoute utilement le bloc de code suivant:

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

Renvoyer l'objet IEnumerable non générique à partir de la méthode GetEnumerator(); ne fonctionne pas cette fois-ci, alors qu'est-ce que je mets ici? La CLI ignore maintenant l'implémentation non générique et se dirige directement vers la version générique lorsqu'elle tente d'énumérer dans mon tableau au cours de la boucle foreach.

114
JMK

Si vous choisissez d'utiliser une collection générique, telle que List<MyObject> au lieu de ArrayList, le List<MyObject> fournira des énumérateurs génériques et non génériques que vous pourrez utiliser.

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();
    }
}
138
Monroe Thomas

Vous ne voulez probablement pas une implémentation de explicite de IEnumerable<T> (ce que vous avez montré).

Le modèle habituel est d'utiliser IEnumerable<T> 'GetEnumerator dans l'implémentation explicite de IEnumerable:

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();
    }
}
56
user7116

Pourquoi le faites-vous manuellement? yield return automatise l'intégralité du processus de traitement des itérateurs. (J'ai aussi écrit à ce sujet sur mon blog , y compris un aperçu du code généré par le compilateur).

Si vous voulez vraiment le faire vous-même, vous devez également renvoyer un énumérateur générique. Vous ne pourrez plus utiliser un ArrayList puisque ce n'est pas générique. Remplacez-le par un _List<MyObject>_. Bien entendu, cela suppose que vous n’ayez que des objets de type MyObject (ou des types dérivés) dans votre collection.

24
Anders Abel

Si vous travaillez avec des génériques, utilisez List au lieu de ArrayList. La liste contient exactement la méthode GetEnumerator dont vous avez besoin.

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

faire de mylist un List<MyObject>, est une option

0
ColWhi