Rendere utilizzabile una classe Visual C# in un'istruzione foreach

Questo articolo illustra come usare le IEnumerable interfacce e IEnumerator per creare una classe che è possibile usare in un'istruzione foreach .

Versione originale del prodotto: Visual Studio
Numero KB originale: 322022

Interfaccia IEnumerator

IEnumerable e IEnumerator vengono spesso usati insieme. Anche se queste interfacce sono simili (e hanno nomi simili), hanno scopi diversi.

L'interfaccia IEnumerator fornisce funzionalità iterative per una raccolta interna a una classe. IEnumerator richiede l'implementazione di tre metodi:

  • Il MoveNext metodo , che incrementa l'indice della raccolta di 1 e restituisce un valore bool che indica se è stata raggiunta la fine della raccolta.

  • Metodo Reset che reimposta l'indice della raccolta sul valore iniziale di -1. Ciò invalida l'enumeratore.

  • Metodo Current , che restituisce l'oggetto corrente in corrispondenza di position.

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

Interfaccia IEnumerable

L'interfaccia IEnumerable fornisce il supporto per l'iterazione foreach . IEnumerable richiede l'implementazione del GetEnumerator metodo .

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

Quando usare l'interfaccia

Inizialmente, l'uso di queste interfacce potrebbe creare confusione. L'interfaccia IEnumerator fornisce l'iterazione su un oggetto di tipo raccolta in una classe. L'interfaccia IEnumerable consente l'enumerazione tramite un foreach ciclo . Tuttavia, il GetEnumerator metodo dell'interfaccia IEnumerable restituisce un'interfaccia IEnumerator . Per implementare IEnumerable, è quindi necessario implementare IEnumeratoranche . Se non si implementa IEnumerator, non è possibile eseguire il cast del valore restituito dal GetEnumerator metodo di IEnumerable all'interfaccia IEnumerator .

In sintesi, l'uso di IEnumerable richiede che la classe implementi IEnumerator. Se si vuole fornire il supporto per foreach, implementare entrambe le interfacce.

Esempio dettagliato

Nell'esempio seguente viene illustrato come usare queste interfacce. In questo esempio le IEnumerator interfacce e IEnumerable vengono usate in una classe denominata cars. La cars classe ha una matrice interna di car oggetti . Le applicazioni client possono enumerare tramite questa matrice interna usando un foreach costrutto a causa dell'implementazione di queste due interfacce.

  1. Seguire questa procedura per creare un nuovo progetto applicazione console in Visual C#:

    1. Avviare Microsoft Visual Studio .NET o Visual Studio.
    2. Scegliere Nuovo dal menu File, quindi fare clic su Progetto.
    3. Fare clic su Progetti Visual C# in Tipi di progetto e quindi su Applicazione console in Modelli.
    4. Nella casella Nome digitare ConsoleEnum.
  2. Rinominare Class1.cs in host.cs e quindi sostituire il codice in host.cs con il codice seguente:

    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. Scegliere Aggiungi classe dal menu Progetto e quindi digitare l'auto nella casella Nome.

  4. Sostituire il codice in car.cs con il codice seguente:

    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. Scegliere Aggiungi classe dal menu Progetto per aggiungere un'altra classe al progetto e quindi digitare automobili nella casella Nome.

  6. Sostituire il codice in cars.cs con il codice seguente:

    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. Eseguire il progetto.

Nella finestra Console viene visualizzato l'output seguente:

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

Procedure consigliate

L'esempio in questo articolo viene mantenuto il più semplice possibile per spiegare meglio l'uso di queste interfacce. Per rendere il codice più affidabile e assicurarsi che il codice usi le linee guida sulle procedure consigliate correnti, modificare il codice come indicato di seguito:

  • Implementare IEnumerator in una classe annidata in modo che sia possibile creare più enumeratori.
  • Fornire la gestione delle eccezioni per il Current metodo di IEnumerator. Se il contenuto della raccolta cambia, viene chiamato il reset metodo . Di conseguenza, l'enumeratore corrente viene invalidato e si riceve un'eccezione IndexOutOfRangeException . Anche altre circostanze potrebbero causare questa eccezione. Implementare quindi un Try...Catch blocco per intercettare questa eccezione e generare un'eccezione InvalidOperationException .
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);
      }
    }
}