166 votes

Comment implémenter IEnumerable<T> ?

Je sais comment implémenter l'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, je remarque également que IEnumerable a une version générique, IEnumerable<T> mais je n'arrive pas à comprendre comment le mettre en œuvre.

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

class MyObjects : IEnumerable

à :

class MyObjects : IEnumerable<MyObject>

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

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

Renvoi de l'objet non générique IEnumerable à partir de l'objet GetEnumerator(); ne fonctionne pas cette fois-ci, alors que dois-je mettre ici ? Le CLI ignore maintenant l'implémentation non générique et se dirige directement vers la version générique lorsqu'il essaie d'énumérer mon tableau pendant la boucle foreach.

86voto

user7116 Points 39829

Vous ne voulez probablement pas d'un explicite la mise en œuvre de IEnumerable<T> (ce que vous avez montré).

Le schéma habituel consiste à utiliser IEnumerable<T> 's GetEnumerator dans l'impl explicite 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();
    }
}

26voto

Anders Abel Points 36203

Pourquoi le faire manuellement ? yield return automatise l'ensemble du processus de gestion des itérateurs. (J'ai également é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 pas utiliser un ArrayList car elle n'est pas générique. Remplacez-la par un List<MyObject> au lieu de cela. Cela suppose bien sûr que vous n'ayez que des objets de type MyObject (ou des types dérivés) dans votre collection.

5voto

Amiram Korach Points 7101

I

List<MyObject> myList = new List<MyObject>();

0voto

ColWhi Points 1064

Transformer ma liste en un List<MyObject> est une option

0voto

Shahar Shukrani Points 522

Il convient de noter que le IEnumerable<T> déjà mis en œuvre par la System.Collections Une autre approche consiste donc à dériver votre MyObjects de la classe System.Collections comme classe de base ( la documentation ) :

System.Collections : Fournit la classe de base pour une collection générique.

Nous pourrons par la suite créer notre propre implémentation pour surcharger la fonction virtuelle System.Collections pour fournir un comportement personnalisé (uniquement pour les méthodes ClearItems , InsertItem , RemoveItem y SetItem ainsi que Equals , GetHashCode y ToString de Object ). Contrairement à l List<T> qui n'est pas conçu pour être facilement extensible.

Exemple :

public class FooCollection : System.Collections<Foo>
{
    //...
    protected override void InsertItem(int index, Foo newItem)
    {
        base.InsertItem(index, newItem);     
        Console.Write("An item was successfully inserted to MyCollection!");
    }
}

public static void Main()
{
    FooCollection fooCollection = new FooCollection();
    fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}

Veuillez noter que la conduite à partir de collection recommandé uniquement dans le cas où un comportement de collection personnalisé est nécessaire, ce qui est rarement le cas. voir utilisation .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X