Rendre une classe Visual C# utilisable dans une instruction foreach

Cet article explique comment utiliser les IEnumerable interfaces et IEnumerator pour créer une classe que vous pouvez utiliser dans une foreach instruction .

Version de produit d’origine : Visual Studio
Numéro de la base de connaissances d’origine : 322022

Interface IEnumerator

IEnumerable et IEnumerator sont fréquemment utilisés ensemble. Bien que ces interfaces soient similaires (et ont des noms similaires), elles ont des objectifs différents.

L’interface IEnumerator fournit une fonctionnalité itérative pour une collection interne à une classe. IEnumerator nécessite que vous implémentiez trois méthodes :

  • La MoveNext méthode , qui incrémente l’index de collection de 1 et retourne un bool qui indique si la fin de la collection a été atteinte.

  • La Reset méthode , qui rétablit la valeur initiale de l’index de la collection à -1. Cela invalide l’énumérateur.

  • Méthode Current , qui retourne l’objet actuel à position.

    public bool MoveNext()
    {
        position++;
        return (position < carlist.Length);
    }
    public void Reset()
    {
        position = -1;
    }
    public object Current
    {
        get { return carlist[position];}
    }
    

Interface IEnumerable

L’interface IEnumerable prend en charge l’itération foreach . IEnumerable nécessite que vous implémentiez la GetEnumerator méthode .

public IEnumerator GetEnumerator()
{
    return (IEnumerator)this;
}

Quand utiliser quelle interface

Au départ, vous pouvez trouver confus l’utilisation de ces interfaces. L’interface IEnumerator fournit une itération sur un objet de type collection dans une classe . L’interface IEnumerable autorise l’énumération à l’aide d’une foreach boucle. Toutefois, la GetEnumerator méthode de l’interface IEnumerable retourne une IEnumerator interface. Par conséquent, pour implémenter IEnumerable, vous devez également implémenter IEnumerator. Si vous n’implémentez IEnumeratorpas , vous ne pouvez pas convertir la valeur de retour de la GetEnumerator méthode de IEnumerable vers l’interface IEnumerator .

En résumé, l’utilisation de IEnumerable nécessite que la classe implémente IEnumerator. Si vous souhaitez assurer la prise en charge de foreach, implémentez les deux interfaces.

Exemple pas à pas

L’exemple suivant montre comment utiliser ces interfaces. Dans cet exemple, les IEnumerator interfaces et IEnumerable sont utilisées dans une classe nommée cars. La cars classe a un tableau interne d’objets car . Les applications clientes peuvent énumérer dans ce tableau interne à l’aide d’une foreach construction en raison de l’implémentation de ces deux interfaces.

  1. Procédez comme suit pour créer un projet d’application console dans Visual C# :

    1. Démarrez Microsoft Visual Studio .NET ou Visual Studio.
    2. On the File menu, point to New, and then click Project.
    3. Cliquez sur Projets Visual C# sous Types de projets, puis sur Application console sous Modèles.
    4. Dans la zone Nom , tapez ConsoleEnum.
  2. Renommez Class1.csen host.cs, puis remplacez le code dans host.cs par le code suivant :

    using System;
    namespace ConsoleEnum
    {
       class host
       {
           [STAThread]
           static void Main(string[] args)
           {
               cars C = new cars();
               Console.WriteLine("\nInternal Collection (Unsorted - IEnumerable,Enumerator)\n");
               foreach(car c in C)
               Console.WriteLine(c.Make + "\t\t" + c.Year);
               Console.ReadLine();
           }
       }
    }
    
  3. Dans le menu Projet , cliquez sur Ajouter une classe, puis tapez car dans la zone Nom .

  4. Remplacez le code dans car.cs par le code suivant :

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
       public class car
       {
           private int year;
           private string make;
           public car(string Make,int Year)
           {
               make=Make;
               year=Year;
           }
           public int Year
           {
               get  {return year;}
               set {year=value;}
           }
           public string Make
           {
               get {return make;}
               set {make=value;}
           }
       }//end class
    }//end namespace
    
  5. Dans le menu Projet , cliquez sur Ajouter une classe pour ajouter une autre classe au projet, puis tapez cars dans la zone Nom .

  6. Remplacez le code dans cars.cs par le code suivant :

    using System;
    using System.Collections;
    namespace ConsoleEnum
    {
        public class cars : IEnumerator,IEnumerable
        {
           private car[] carlist;
           int position = -1;
           //Create internal array in constructor.
           public cars()
           {
               carlist= new car[6]
               {
                   new car("Ford",1992),
                   new car("Fiat",1988),
                   new car("Buick",1932),
                   new car("Ford",1932),
                   new car("Dodge",1999),
                   new car("Honda",1977)
               };
           }
           //IEnumerator and IEnumerable require these methods.
           public IEnumerator GetEnumerator()
           {
               return (IEnumerator)this;
           }
           //IEnumerator
           public bool MoveNext()
           {
               position++;
               return (position < carlist.Length);
           }
           //IEnumerable
           public void Reset()
           {
               position = -1;
           }
           //IEnumerable
           public object Current
           {
               get { return carlist[position];}
           }
        }
      }
    
  7. Exécutez le projet.

La sortie suivante s’affiche dans la fenêtre console :

Ford            1992
Fiat            1988
Buick           1932
Ford            1932
Dodge           1999
Honda           1977

Meilleures pratiques

L’exemple de cet article est aussi simple que possible pour mieux expliquer l’utilisation de ces interfaces. Pour rendre le code plus robuste et s’assurer que le code utilise les bonnes pratiques actuelles, modifiez le code comme suit :

  • Implémentez IEnumerator dans une classe imbriquée afin de pouvoir créer plusieurs énumérateurs.
  • Fournissez la gestion des exceptions pour la Current méthode de IEnumerator. Si le contenu de la collection change, la reset méthode est appelée. Par conséquent, l’énumérateur actuel est invalidé et vous recevez une IndexOutOfRangeException exception. D’autres circonstances peuvent également provoquer cette exception. Implémentez donc un Try...Catch bloc pour intercepter cette exception et lever une InvalidOperationException exception.
using System;
using System.Collections;
namespace ConsoleEnum
{
    public class cars : IEnumerable
    {
        private car[] carlist;
  
        //Create internal array in constructor.
        public cars()
        {
            carlist= new car[6]
            {
                new car("Ford",1992),
                new car("Fiat",1988),
                new car("Buick",1932),
                new car("Ford",1932),
                new car("Dodge",1999),
                new car("Honda",1977)
            };
        }
        //private enumerator class
        private class  MyEnumerator:IEnumerator
        {
            public car[] carlist;
            int position = -1;

            //constructor
            public MyEnumerator(car[] list)
            {
                carlist=list;
            }
            private IEnumerator getEnumerator()
            {
                return (IEnumerator)this;
            }
            //IEnumerator
            public bool MoveNext()
            {
                position++;
                return (position < carlist.Length);
            }
            //IEnumerator
            public void Reset()
            {
                position = -1;
            }
            //IEnumerator
            public object Current
            {
                get
                {
                    try
                    {
                        return carlist[position];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        throw new InvalidOperationException();
                    }
                }
            }
        }  //end nested class
      public IEnumerator GetEnumerator()
      {
          return new MyEnumerator(carlist);
      }
    }
}