.NET
- As interface IEnumerable e IEnumerator
![]() |
A plataforma .NET tem evoluído continuamente fornecendo recursos cada vez mais avançados para o tratamento de coleções. |
Para podermos tratar uma coleção de informações temos que escrever e executar consultas e realizar iterações sobre o resultado.
Quando o assunto é realizar iterações sobre coleções devemos conhecer bem duas interfaces: IEnumerable e IEnumerator.
A interface IEnumerable suporta uma iteração sobre uma coleção não genérica. A interface possui apenas o método GetEnumerator que retorna um enumerador que itera sobre a coleção.
A interface IEnumerator suporta uma iteração simples sobre uma coleção sendo a interface base para todos os enumeradores.
As interfaces IEnumerable e IEnumerator estão no namespace System.Collections.
A hierarquia de interface deste namespace pode ser visto na figura abaixo:
![]() |
IEnumerable
- É a base direta ou indiretamente para algumas outras Interfaces
e todas as coleções a implementam. Esta interface tem
apenas um método a ser implementado, chamado GetEnumerator,
qual retorna um objeto do tipo da Interface de IEnumerator. IEnumerator - É a base para todos os enumeradores. Composta por uma propriedade Current e dois métodos moveNext e Reset), percorre e lê todos os elementos de uma determinada coleção, permitindo apenas ler os dados, não podendo alterá-los. Vale levar em consideração que enumeradores não podem ser utilizados para a coleção subjacente. ICollection - É a Interface base para todas as coleções que estão contidas dentro do namespace System.Collections. Direta ou indiretamente essas classes a implementa. Ela por sua vez é composta por três propriedades Count, IsSynchronized e SyncRoot e um método CopyTo.
|
A interface IEnumerator possui os seguintes membros:
Abaixo uma figura que mostra como funcionam os membros do IEnumerator:(fonte: http://www.codeproject.com/KB/cs/sssienumerable.aspx)
![]() |
Vejamos o funcionamentos destes membros:
Um enumerador permanece válido, desde que a coleção permaneça inalterada. Se forem feitas alterações na coleção, como adicionar, modificar ou excluir elementos, o enumerador ficará invalidado e a próxima chamada para MoveNext ou Reset gera uma exceção InvalidOperationException. Se a coleção é modificado entre MoveNext e Current, Current retornará o elemento que é definido, mesmo se o enumerador está já invalidado.
A instrução foreach (linguagem C#)/for each (Visual Basic) oculta a complexidade dos enumeradores. Portanto é recomendável usar foreach/for each ao invés de tentar manipular diretamente o enumerador. (Os enumeradores podem ser usados para ler dados em um coleção mas não podem modificar estes dados.)
Implementando as interface IEnumerable e IEnumerator
Crie um novo projeto usando o Visual Basic 2010 Express Edition do tipo Console Application com o nome IEnumerable_Exemplo1:
Public Class TimesEnumerator
Implements IEnumerator
Private times() As String = {"Santos", "São Paulo", "Palmeiras", "Corintians", "Flamengo", "Vasco"}
Private posicao As Integer = -1
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
If Me.posicao < 0 OrElse Me.posicao > 4 Then
Throw New InvalidOperationException
Else
Return Me.times(Me.posicao)
End If
End Get
End Property
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
Me.posicao += 1
Return Me.posicao <= 4
End Function
Public Sub Reset() Implements IEnumerator.Reset
Me.posicao = -1
End Sub
End Class
|
No código acima criamos a classe TimesEnumerator e implementamos a interface IEnumerator; dessa forma tivemos que definir os métodos: MoveNext() e Reset() e a propriedade Current.
Se você quiser exibir os valores do array de strings times() terá que usar um laço for/next e verificar se o método retorna True ou False para em seguida usar a propriedade Current para recuperar o item da coleção.
Uma maneira mais simples seria usar um laço For/Each mas para isso teremos que criar uma classe auxiliar implementando a interface IEnumerable que possui o método GetEnumerator que retornará uma instância da classe TimesEnumerator.
Public Class Times
Implements IEnumerable
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return New TimesEnumerator()
End Function
End Class
|
Agora já podemos usar o laço For/Each para iterar sobre a coleção:
| For Each
time As String In New Times() Console.WriteLine(time) Next |
Executando o projeto teremos o seguinte resultado:
![]() |
Vamos então criar outro exemplo mais completo usando ambas a interfaces e o laço For/Each.
Vejamos um exemplo simples de implementação das interfaces IEnumerable e IEnumerator para uma coleção customizada. No exemplo os membros destas interfaces foram implementados para realizar a iteração sobre uma coleção usando for each.
Crie um novo projeto usando o Visual Basic 2010 Express Edition do tipo Console Application com o nome IEnumerable_Exemplo2:
Imports System.Collections
Module Module1
Sub Main()
Dim pessoasArray() As Pessoa = { _
New Pessoa("Macoratti", "macoratti@yahoo.com"), _
New Pessoa("Miriam", "miriam@hotmail.com"), _
New Pessoa("Jefferson", "jeff@bol.com.br")}
Dim pessoasNaLista As New Pessoas(pessoasArray)
Dim p As Pessoa
For Each p In pessoasNaLista
Console.WriteLine(p.Nome + " " + p.Email)
Next
Console.ReadKey()
End Sub
Public Class Pessoa
Public Sub New(ByVal _nome As String, ByVal _email As String)
Me.Nome = _nome
Me.Email = _email
End Sub
Public Nome As String
Public Email As String
End Class
Public Class Pessoas
Implements IEnumerable
Private _pessoas() As Pessoa
Public Sub New(ByVal pArray() As Pessoa)
_pessoas = New Pessoa(pArray.Length - 1) {}
Dim i As Integer
For i = 0 To pArray.Length - 1
_pessoas(i) = pArray(i)
Next i
End Sub
Public Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return New PessoasEnum(_pessoas)
End Function
End Class
Public Class PessoasEnum
Implements IEnumerator
Public _pessoas() As Pessoa
' Enumeradores são posicionados antes do primeiro elemento
' ate que o m´metodo MoveNext() seja chamado
Dim posicao As Integer = -1
Public Sub New(ByVal lista() As Pessoa)
_pessoas = lista
End Sub
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
posicao = posicao + 1
Return (posicao < _pessoas.Length)
End Function
Public Sub Reset() Implements IEnumerator.Reset
posicao = -1
End Sub
Public ReadOnly Property Current() As Object Implements IEnumerator.Current
Get
Try
Return _pessoas(posicao)
Catch ex As IndexOutOfRangeException
Throw New InvalidOperationException()
End Try
End Get
End Property
End Class
End Module
|
||
Criamos a classe Pessoa
contendo as propriedades :
Criamos a classe Pessoas que implementa a interface IEnumerable. Nesta classe definimos o método GetEnumerator() Definimos a classe PessoaEnum que implementa a interface IEnumerator Nesta classe definimos os métodos:
e a propriedade
No método Main()
instanciamos a classe Pessoa e criamos
alguns objetos do Criamos uma instância da classe Pessoas passando o array de pessoas. A seguir percorremos a coleção usando um For Each. Executando o projeto teremos o seguinte resultado:
|
Se você conhece a sintaxe da linguagem Visual Basic deve lembrar que para percorrer uma coleção fazíamos assim:
For i = 1 to
fimdaColeção
'
Fazer alguma coisa com a Coleção(i)
Next i
No Visual Basic .NET temos a sintaxe:
For Each
elemento in Coleção
' Fazer alguma
coisa com o elemento
Next element
Uma das razões pela qual a sintaxe VB .NET - For Each - é melhor é que você não tem que saber onde a coleção começa e termina. O VB .NET faz isso para você.
Pegue o projeto completo
aqui:
IEnumerable_Exemplo.zip
"Eu sou a luz que vim ao mundo, para que todo aquele que crê em mim não permaneça nas trevas." João 12:46
Referências: