Desenvolvimento - Visual Basic .NET
Usando coleções com Visual Basic .NET
Todas as coleções existentes no Microsoft .NET Framework derivam, direta ou indiretamente da interface ICollection, sob o namespace System.Collections, compartilhando muitas funcionalidades mais os tradicionais métodos para adicionar, remover e buscar elementos...
por Wallace Cézar Sales dos SantosUma coleção é um conjunto de objetos similarmente tipados que são agrupados num único objeto.
Todas as coleções existentes no Microsoft .NET Framework derivam, direta ou indiretamente da interface ICollection, sob o namespace System.Collections, compartilhando muitas funcionalidades mais os tradicionais métodos para adicionar, remover e buscar elementos.
Algumas dessas funcionalidades incluem enumeradores, que são objetos que permitem e realizam repetições através de uma única coleção associada, membros de sincronização, que fornecem segurança no thread quando acessando elementos da coleção e métodos para cópias, através do uso do método CopyTo, que permite que as coleções possam ser copiadas para um array.
As coleções podem geralmente serem divididas em três categorias:
- Coleções genéricas – são as variações mais comuns de coleções de dados, como hash tables, filas, pilha, dicionários e listas;
- Coleções de Bits – são as coleções onde os elementos são bits sinalizadores. Elas comportam-se levemente diferente das outras coleções;
- Coleções especializadas – são as coleções construídas com propósitos altamente definidos, usualmente para manipular tipos de elementos específicos, como a StringDictionary. Coleções podem variar, dependendo de como os elementos são armazenados, como são classificados, como as buscas são realizadas e como as comparações são realizadas.
Como já exposto, coleções genéricas são são as variações mais comuns de coleções de dados, como hash tables, filas, pilha, dicionários e listas. Essas coleções são baseadas nas interfaces ICollection , IList ou IDictionary. As interfaces IList e IDictionary implementam a interface ICollection. As coleções baseadas na interfaces ICollection e IList possuem elementos que contém somente um valor (Array, ArrayList, Queue ou Stack). As coleções baseadas na interface IDictionary implementam elementos que contém valor e chave (Hashtable, SortedList).
As classes System.Collection.Queue e System.Collection.Stack são ideais para armazenamento temporário de informação, ou seja quando desejamos descartar o elemento após retirar seu valor. A diferença entre as duas reside no fato da primeira criar uma coleção onde o primeiro elemento a entrar é o primeiro a sair da coleção e na segunda, o oposto.
Shared Sub ExecQueue()
Dim q As New
System.Collections.Queue
q.Enqueue("Desenvolvendo")
q.Enqueue(" com
")
q.Enqueue("VB.NET")
Console.WriteLine("Número de elementos: {0}", q.Count)
Console.WriteLine("Elementos existentes:")
Dim i As
Int32
For i = 0 To q.Count -
1
Console.Write(q.Dequeue())
Next
End Sub
Listagem 1 – Acessando a classe System.Collection.Queue
A classe Queue (acessada na listagem 1), assim como a classe Stack, não possue uma propriedade Item. Na prática, isso quer dizer que não podemos acessar seus elementos pelo seu índice. A classe Queue nos fornece o método Enqueue com a finalidade de adicionarmos um tipo Object à coleção e o método Dequeue com a finalidade de retornar e retirar um elemento da coleção. Observe que para adicionarmos, passamos como argumento um objeto, porém para retirar não informamos qual desejamos: o primeiro a entrar é o primeiro a sair! Para podermos verificar um elemento sem retirá-lo da coleção, ambas as classes nos fornecem o método Peek para essa finalidade.
A classe System.Collection.Hashtable (acessada na listagem 2) é uma classe em que cada elemento da coleção é representado por um par de chave e valor. Uma Hashtable consiste num depósito que contém os elementos da coleção, funcionando como um subgrupo virtual e que realiza a busca e retirada dos elementos de forma mais rápida e fácil que a maioria das coleções. Isto é possível porque cada depósito é associado com um código hash baseado no valor do elemento.
Shared Sub ExecHashtable()
Dim h As New System.Collections.Hashtable(3)
h.Add(1, "Desenvolvendo")
h.Add(2, " com
")
h.Add(3, "VB.NET")
Console.WriteLine("Trabalhando com a coleção Hashtable")
Console.WriteLine("Número de elementos: {0}", h.Count)
Console.WriteLine("Apresentando as informações: ")
Dim i As
Int32
For i = 1 To h.Count
Console.WriteLine("Chave-> {0} : Valor-> {1}",
_
i.ToString(),
h.Item(i))
Next
Console.WriteLine("Removendo o
item com a chave 2, utilizando o método Remove:")
h.Remove(2)
Console.WriteLine("{0} {1}", h.Item(1),
h.Item(3))
End Sub
Listagem 2 – Acessando a classe System.Collection.Hashtable
A primeira grande diferença que notamos é o fato de podermos realizar acesso aleatório aos elementos da coleção, através da propriedade item e o valor da chave (Key) permitindo-nos o acesso rápido ao valor contido na coleção. Podemos também, através do método Remove, retirar qualquer elemento da coleção, informando o valor de sua propriedade Key. Um outro ponto muito importante do uso da coleção Hashtable está no momento em que executamos o construtor seu construtor – Dim h As New System.Collections.Hashtable(3) – onde informamos o número inteiro 3, que define a capacidade da nossa coleção, único momento em que podemos realizar essa tarefa e que melhora sensivelmente a performance de de nossa coleção, pois elimina a necessidade de redimensionamento da coleção a medida que são adicionados novos elementos.
A classe System.Collection.ArrayList (acessada na listagem 3) é o que podemos chamar de evolução do Array. Possue funcionalidades típicas de coleções e que não são oferecidas pelo Array:
- Não possue capacidade fixa como um Array, sendo automaticamente expandida quando necessário;
- Fornece métodos que adiciona, insere ou remove vários elementos de uma vez. O Array somente é possível adicionar ou remover um elemento por vez;
- Uma versão sincronizada é fácil de criar utilizando o método Synchronized. Com array não é tão simples;
- Fornece métodos que retornam conectores “read-only” e “fixed-size” para uma coleção. Array não realiza essa operação.
- Você não pode definir o limite inferior da coleção. Ela sempre se iniciará com zero, diferente do Array que é possível definir outro valor;
- Possue somente uma dimensão. Um Array pode ser multidimensional;
- Possui performance pior que um Array, se este for de um tipo específico. Isto ocorre porque os elementos do ArrayList são do tipo Object e, assim sendo, são necessárias operações de “boxing” e “unboxing” para armazenar e retirar os elementos da coleção, consumindo mais recursos do sistema.
Dim al As New System.Collections.ArrayList(3)
al.Add("Desenvolvendo")
al.Add(" com ")
al.Add("VB.NET")
Console.WriteLine("Trabalhando com a coleção ArrayList")
Console.WriteLine("Número de elementos: {0}", al.Count)
Console.WriteLine("Apresentando as informações: ")
Dim i As Int32
For i = 0 To al.Count - 1
Console.Write("{0}", al.Item(i))
Next
Console.WriteLine("Removendo o item com índice 1, utilizando o método RemoveAt:")
al.RemoveAt(1)
For i = 0 To al.Count - 1
Console.Write("{0} ", al.Item(i))
Next
End Sub
Listagem 3 – Acessando a classe System.Collection.ArrayList
Da mesma forma que vimos na classe Hashtable, podemos também realizar acesso aleatório aos elementos da coleção.
Coleções de Bits
Coleções de Bits são aquelas onde os elementos são bits sinalizadores. Isto ocorre porque cada elemento é um bit e não um objeto e consequentemente, tem um comportamento levemente diferente das demais coleções.
A classe System.Collections.BitArray é uma classe que gerencia um compacto array de bits, os quais são representados como booleans, onde o valor true indica indica que o bit é “1” e false indica que o bit é “0”. Sua capacidade é sempre igual ao valor da sua propriedade Count. Se elementos são adicionados, a propriedade Lengh é incrementada, se são retirados, ela é decrementada. Como trata-se de uma coleção que manipula bits, ela possue métodos que não são encontrados em outras coleções, métodos esses próprios para a manipulação de bits: And, Or, Xor, Not e SetAll. Esse métodos permitem que múltiplos elementos sejam modificados uma única vez.
Shared Sub ExecBitArray()
Dim ba As New
System.Collections.BitArray(3)
Console.WriteLine("Propriedade Length: {0}; Propriedade Count: {1}", ba.Length,
ba.Count)
Dim i As Int32
For i = 0 To ba.Count -
1
Console.WriteLine("Valor do Bit
{0}: {1}", i, ba.Item(i))
Next
Console.WriteLine("Alterando os
valores para true, através do método SetAll:")
ba.SetAll(True)
For i = 0 To ba.Count -
1
Console.WriteLine("Valor do Bit
{0}: {1}", i, ba.Item(i))
Next
Console.WriteLine("Alterando o
valor do segundo Bit para False:")
ba.Item(1) =
False
For i = 0 To ba.Count -
1
Console.WriteLine("Valor do Bit
{0}: {1}", i, ba.Item(i))
Next
Console.WriteLine("Criando um
novo BitArray e definindo os elementos como um array de
inteiros:")
Dim mArray As Int32() = New Int32(1) {1,
2}
Dim ba1 As New
System.Collections.BitArray(mArray)
For i = 0 To ba1.Count -
1
Console.WriteLine("Valor do Bit
{0}: {1}", i, ba1.Item(i))
Next
End Sub
Listagem 4 – Acessando a classe System.Collection.BitArray
Observando a listagem 4, verificamos que inicializamos o objeto “ba” informando o número de bits iniciais: “3”. O construtor da classe BitArray possue várias sobrecargas, permitindo-nos inicializar informando quantos bits estarão sendo armazenados na coleção e, neste caso, todos com o valor padrão false ou, entre outras opções, realizar a inicialização informando um array de inteiros, como no caso da inicialização do objeto “ba1”. Lembrando que nossa coleção armazena bits, e que um inteiro possui 32 bits, o nosso objeto “ba1” tem como tamanho inicial – propriedade Lenght – o valor 64. Podemos também alterar o valor de todos os bits usando o método SetAll e pudemos também realizar o acesso aleatório a um bit desejado, alterando o seu valor.
Para operações com bits onde o tamanho não ultrapassar um inteiro de 32 bits, o ideal é que seja utilizada a estrutura System.Collections.Specialized.BitVector32, que oferece as mesmas funcionalidades que a classe BitArray, mas possui uma performance melhor por se tratar de um tipo por valor, enquanto a classe BitArray é um tipo por referência.
Coleções especializadas
Tratam-se de coleções construídas com propósitos altamente definidos, especializadas e com tipos fortemente definidos.
A classe System.Collections.Specialized.StringDictionary é um exemplo. Ela implementa uma hashtable com a chave fortemente tipada para ser um tipo String ao invés de um tipo Object. Vejamos o seu uso:
Shared Sub ExecStringDictionary()
Dim sd As New
System.Collections.Specialized.StringDictionary
Console.WriteLine("Trabalhando com a coleção especializada
StringDictionary.")
sd.Add("0", "Usando coleções com
VB.NET")
sd.Add("1", "Wallace
Santos")
Console.WriteLine("Número de elementos da
coleção: {0}", sd.Count)
Dim i
As Int32
For i = 0 To sd.Count -
1
Console.WriteLine("O Valor para
a chave {0} é: {1}", i, sd.Item(i))
Next
End Sub
Listagem 5 – Acessando a classe System.Collection.Specialized.StringDictionary
A classe StringDictionary é preenchida exclusivamente por strings e, portanto, não possui um índice numérico. A localização de qualquer elemento dentro da coleção pode ser realizada através da verificação do valor da propriedade Keys, que implementa a interface ICollection (internamente utiliza uma classe Hashtable). É importante saber que a ordem das chaves e valores dos elementos não é especificado. Isso quer dizer que o resultado da execução da sentença For da listagem 5 não será necessariamente a mesma de entrada dos elementos.
Como escolher a opção correta
As opções para escolhermos a coleção a ser usada em cada situação são muitas. É necessário muito cuidado para esta tarefa, pois cada uma tem as suas próprias funcionalidades e limitações, restringindo o uso da coleção. Para escolher a coleção correta a ser utilizada, considere as seguintes questões:
- Existe a necessidade de uma lista sequêncial, onde o elemento é tipicamente descartado após o valor ser retirado? Se a resposta for sim, considere o uso da Queue ou Stack;
- Existe a necessidade de acessar os elementos numa certa ordem, do tipo primeiro a entrar, primeiro a sair, ou último a entrar, primeiro a sair, ou acesso randômico? Queue oferece acesso do tipo primeiro a entrar, primeiro a sair (first-in-first-out), Stack oferece acesso do tipo último a entrar, primeiro a sair (last-in-first-out). As demais coleções oferecem acesso randômico;
- Existe a necessidade de acessar cada elemento por um índice? As classes ArrayList e StringCollection oferecem acesso a seus elementos através de indices baseado em zero (zero-based index). As coleções Hashtable, SortedList, ListDictionary e StringDictionary oferecem acesso a seus elementos através do uso da chave do elemento. As coleções NameObjectCollectionBase e NameValueCollection oferecem acesso através de uma combinação das opções já citadas;
- Existe a necessidade de que cada elemento contenha um valor ou, a combinação de uma chave e um valor ou ainda uma combinação de uma chave e múltiplos valores? No caso de um valor, use qualquer coleção baseada na interface IList, no caso uma chave e um valor, use qualquer classe baseada na interface IDictionary e no caso de uma chave e múltiplos valores, utilize a classe NameValueCollection;
- Existe a necessidade de classificar os elementos de forma diferente de como eles foram informados? Neste caso temos 3 opções: Hashtable, que classifica os elementos pelo código hash (sistema de codificação derivado do código ASCII) da chave, SortedList, que classifica os elementos pela sua chave, baseado na implementação da interface IComparer e ArrayList, que fornece um método de classificação (Sort) que recebe a interface IComparer como parâmetro;
- Existe a necessidade de realizar buscas rápidas e retirar a informação? ListDictionary é mais rápido que Hashtable em pequenas coleções (dez itens ou menos);
- e Existe a necessidade de coleções que aceitem somente strings? StringCollection (baseada na interface IList) e StringDictionary (baseada na interface IDictionary) são especializadas nessa tarefa.
Conclusão
As opções para escolhermos a coleção a ser usada em cada situação são muitas. Coleções são um recurso interessante e poderoso que temos nas nossas mãos. Seu uso deve ser consciente e agora podemos fazer isso.
- Entity Framework 4: Repositório GenéricoVisual Basic .NET
- As edições 14 da Easy .net Magazine e 88 da .net Magazine já estão disponíveis.ADO.NET
- Postando no Twiiter com .NET e Migre.meC#
- Setup ApplicationsVisual Basic .NET
- Problemas na manipulação de arquivos do MS Excel com .NETVisual Basic .NET