Tornar uma classe do Visual C# utilizável em uma instrução foreach

Este artigo demonstra como usar as IEnumerable interfaces e IEnumerator para criar uma classe que você pode usar em uma foreach instrução.

Versão original do produto: Visual Studio
Número de KB original: 322022

Interface IEnumerator

IEnumerable e IEnumerator são usados com frequência juntos. Embora essas interfaces sejam semelhantes (e tenham nomes semelhantes), elas têm propósitos diferentes.

A IEnumerator interface fornece recursos iterativos para uma coleção que é interna para uma classe. IEnumerator exige que você implemente três métodos:

  • O MoveNext método, que incrementa o índice de coleção em 1 e retorna um bool que indica se o final da coleção foi atingido.

  • O Reset método, que redefine o índice de coleção para seu valor inicial de -1. Isso invalida o enumerador.

  • O Current método, que retorna o objeto atual em position.

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

Interface IEnumerable

A IEnumerable interface fornece suporte para a foreach iteração. IEnumerable exige que você implemente o GetEnumerator método.

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

Quando usar qual interface

Inicialmente, você pode achar confuso usar essas interfaces. A IEnumerator interface fornece iteração sobre um objeto tipo de coleção em uma classe. A IEnumerable interface permite a enumeração usando um foreach loop. No entanto, o GetEnumerator método da IEnumerable interface retorna uma IEnumerator interface. Portanto, para implementar IEnumerable, você também deve implementar IEnumerator. Se você não implementar IEnumerator, não poderá lançar o valor retornado do GetEnumerator método de IEnumerable para a IEnumerator interface.

Em resumo, o uso de IEnumerable requer que a classe implemente IEnumerator. Se você quiser fornecer suporte para foreach, implemente ambas as interfaces.

Exemplo passo a passo

O exemplo a seguir demonstra como usar essas interfaces. Neste exemplo, as IEnumerator interfaces e IEnumerable são usadas em uma classe chamada cars. A cars classe tem uma matriz interna de car objetos. Os aplicativos cliente podem enumerar por meio dessa matriz interna usando um foreach constructo devido à implementação dessas duas interfaces.

  1. Siga estas etapas para criar um novo projeto de Aplicativo de Console no Visual C#:

    1. Inicie o Microsoft Visual Studio .NET ou o Visual Studio.
    2. No menu arquivo, aponte para novo e, em seguida, clique em Project.
    3. Clique em Projetos do Visual C# em Tipos de Projeto e, em seguida, clique em Aplicativo de Console em Modelos.
    4. Na caixa Nome , digite ConsoleEnum.
  2. Renomeie Class1.cs para host.cs e substitua o código no host.cs pelo seguinte código:

    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. No menu Projeto , clique em Adicionar Classe e digite carro na caixa Nome .

  4. Substitua o código no car.cs pelo seguinte código:

    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. No menu Projeto , clique em Adicionar Classe para adicionar outra classe ao projeto e digite carros na caixa Nome .

  6. Substitua o código no cars.cs pelo seguinte código:

    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. Execute o projeto.

A saída a seguir é exibida na janela Console :

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

Práticas recomendadas

O exemplo neste artigo é mantido o mais simples possível para explicar melhor o uso dessas interfaces. Para tornar o código mais robusto e garantir que o código use as diretrizes de prática recomendada atuais, modifique o código da seguinte maneira:

  • Implemente IEnumerator em uma classe aninhada para que você possa criar vários enumeradores.
  • Forneça tratamento de exceção para o Current método de IEnumerator. Se o conteúdo da coleção for alterado, o reset método será chamado. Como resultado, o enumerador atual é invalidado e você recebe uma exceção IndexOutOfRangeException . Outras circunstâncias também podem causar essa exceção. Portanto, implemente um Try...Catch bloco para capturar essa exceção e gerar uma exceção 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);
      }
    }
}