Dev (Back & Front)ARTIGO

.NET – Usando Generics

A versão 2.0
da plataforma .NET introduziu as coleções genéricas que
ficam agrupadas no namespace System.Collections.Generics; Generics permite a definição de tipos em tempo de execução.

Podemos dizer
que Generics são coleções tipadas de modo que
somente um tipo de dado pertença à coleção. Ao se tentar
inserir outro tipo de dado, o compilador irá reclamar. Assim
sabemos o que cada coleção contém e não precisamos fazer a
conversão na hora de retirar um item da coleção.

Estas coleções Generics
são fortemente tipadas, ou seja, estão disponíveis no
intelissense e são verificadas pelo compilador, o que evita
erros e torna mais fácil a vida do desenvolvedor.

Os
problemas que envolvem o uso de coleções no VB.NET
podem ser resumidos da seguinte forma:

  • As
    coleções aceitam qualquer tipo de dados;

  • As
    coleções fazem a conversão implícita dos
    tipos de dados para Object;

  • Ao
    tratarmos os itens das coleções temos que fazer
    o caminho de volta
    Object-> tipo-do-item
    via casting;

  • As
    coleções não exibem suas propriedades no
    intelissense;

  • Tudo
    isto é transparente para o desenvolvedor e a
    depuração pode ser traumática.;

As principais
coleções genéricas são:

  • List(Of 
    T) –  Representa uma lista fortemente tipada de
    objetos que podem ser acessados através de um índice.
    Fornece os métodos Search, Sort e efetua a
    manipulação da lista.

  • LinkdeList(Of 
    T) – Organiza os itens na forma de uma lista
    duplamente ligada.

  • Stack(Of
    T) – Organiza os itens na forma de um pilha.(LIFO –
    last-in first-out)

  • SortedList(Of
    TKey, TValue) – Representa uma coleção de
    pares representados por chave/valor que são
    ordenados pela chave com base na implementação de System.Collections.Generic.IComparable
    associada.

  • SortedDictionary(Of
    TKey, TValue) – Representa uma coleção de
    pares representados por chave/valor que são
    ordenados pela chave.

  • Queue(Of
    T) – Organiza os itens na forma de uma fila.(FIFO –
    first-in firs-out)

Nota: O parâmetro (Of T) na declaração
da lista é obrigatório e indica qual o tipo de dados que
poderá ser incluído na coleção.

Começando pelo começo

Um das coleções
genéricas mais usada é a List(Of (T)), onde se
define o tipo da coleção que se pretende usar.

Vamos iniciar um exemplo
bem simples definindo uma lista do tipo String:

Abra o Visual Basic 2008
Express Edition e crie um novo projeto do tipo Windows
Application com o nome usandoGenerics;

Inclua os seguintes
controles no formulário: ListBox (lstALunos) , TextBox (txtNome)
e Button1 (btnProcurar) e Button2(btnListar) conforme o leiaute
abaixo:

No formulário padrão
form1.vb no início da classe Form1 vamos declarar uma lista do
tipo String:

‘ Cria uma nova
lista do tipo “string”
Dim listaAlunos As New List(Of String)

Onde List(Of T) repesenta
uma lista fortemente tipada que pode ser acessada pelo índice e
fornece métodos para ordenar, procurar e manipular listas.

No evento Load do formulário vamos
popular a lista com nomes:

  Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load<br />        'Inclui nomes na lista<br />        listaAlunos.Add("Macoratti")<br />        listaAlunos.Add("Jefferson")<br />        listaAlunos.Add("Jessica")<br />        listaAlunos.Add("Janice")<br />        listaAlunos.Add("Bianca")<br />        listaAlunos.Add("Yuri")<br />        listaAlunos.Add("Larissa")<br />        listaAlunos.Add("Larissa")<br />        listaAlunos.Add("Madalena")<br />        listaAlunos.Add("Marcia")<br />        listaAlunos.Add("Carlos")<br />    End Sub

Agora no evento Click
do botão de comando inclua o seguinte código:

Private Sub btnProcurar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExibir.Click<br />        Dim nomeAluno As String = txtNome.Text<br />        ' Encontrou o nome<br />        If listaAlunos.Contains(nomeAluno) Then<br />            ' Exibe o nome e o total de nomes<br />            Dim msg As String = "{0} foi encontrado em uma relação de  {1} nome(s)"<br />            lstAlunos.Items.Add(String.Format(msg, nomeAluno, listaAlunos.Count))<br />        Else<br />            ' Não encontrou nome na lista<br />            lstAlunos.Items.Add("Nome não encontrado na lista!")<br />        End If<br />    End Sub

Neste código usamos os seguintes
métodos da lista :

  • Contains – determina se um
    elemento está na lista;
  • Count – obtém o número de
    elementos contidos na lista;

Para listar o conteúdo da lista
incluímos o código abaixo no evento Click do botão Listar:

  Private Sub btnListar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnListar.Click<br />        For i = 0 To listaAlunos.Count - 1<br />            lstAlunos.Items.Add(listaAlunos(i))<br />        Next<br />  End Sub

Como alternativa para listar o
conteúdo de uma lista tipada podemos também usar os seguintes
métodos:

For Each nome As String In listaAlunos<br />      lstAlunos.Items.Add(nome)<br />Next

Usando o loop For
Each
percorremos a lista e exibimos o nome

ou ainda:

    Dim atual As String<br />    Dim en As IEnumerator(Of String) = listaAlunos.GetEnumerator()<br />    While (en.MoveNext())<br />         atual = en.Current<br />        lstAlunos.Items.Add(atual)<br />    End While

Usando o GetEnumerator(),
que é um função da interface IEnumerable, obtemos um enumerator com o qual
podemos
percorrer a coleção usando a função MoveNext().

Quando usamos o MoveNext(),
o enumerator vai para a primeira
posição da coleção e podemos acessar o seu valor
usando a
propriedade Current.

Ao chegar ao final da
coleção para retornar usamos a propriedade Reset.

Se você desejar ordernar a lista,
basta usar a função Sort: listaAlunos.Sort().

Se desejar passar os nomes da lista
para caixa baixa, use o método ToLower. Quer
caixa alta? Então use a função ToUpper.

No exemplo abaixo usamos as
funções Sort para ordernar e ToUpper
para colocar em caixa alta os nomes da lista:

Dim atual<br />        As String<br /><br />        listaAlunos<strong>.Sort()</strong><br /><br />        Dim en As IEnumerator(Of String) = listaAlunos.<strong>GetEnumerator()</strong><br /><br />        While (en.MoveNext())<br /><br />            atual = en.Current.<strong>ToUpper()</strong><br /><br />            lstAlunos.Items.Add(atual)<br /><br />        End While

Com o advento do Generics, podemos
usar um código mais limpo e otimizado em nossas aplicações que
tratam com coleções de dados como as aplicações que usam
Banco de dados Relacionais.

Neste caso podemos criar uma classe
definindo um tipo de dado para a nossa entidade e depois definir
uma lista genérica do tipo da classe que implementamos. Entendeu? Bem, vamos mostrar isso na prática…

Neste exemplo eu vou criar uma
aplicação ASP .NET usando a linguagem VB .NET que terá como
objetivo acessar a tabela Alunos em um banco de dados SQL
Server
Express Edition (Vou usar a versão 2005) e exibir a relação
de alunos em uma página web.

Até agora nada de mais, você pode estar
pensando. A novidade é que eu vou usar generics para obter uma
lista dos alunos que estão na tabela Alunos. Vejamos…

Abra o Visual Web Developer 2008
Express Edition e crie um novo web site usando o template ASP
.NET Web Site com o nome listaAlunosGenerics;

A seguir clique no menu Web Site e
selecione a opção Add new Item e na janela Templates selecione
o template SQL Server DataBase, informe o nome Escola.mdf e
clique em Add;

Clique no botão Sim
para salvar o banco de dados na pasta App_Data:

A seguir abra o banco de dados na
janela DataBase Explorer e crie a tabela Alunos
com a seguinte estrutura:

  • id – int
  • nome – nvarchar(50)
  • email – nvarchar(80)

Clique com o botão direito do mouse
sobre a tabela criada , selecione a opção Show Table
Data
e inclua alguns registros na tabela.

Selecione a página Default.aspx e
inclua um componente GridView com id=gdvAlunos na página:

Agora vamos criar uma classe que
representará a nossa tabela Alunos como uma entidade. Para isso,
no menu Web Site, selecione Add New Item e, em templates, selecione
Class e informe o nome Aluno.vb e clique em Add;

Confirme a opção para salvar o
arquivo na pasta App_Code;

Defina o código abaixo no arquivo
Alunos.vb:

Public Class Aluno<br />    Dim _id As Long<br />    Dim _nome As String<br />    Dim _email As String<br /><br />    ReadOnly Property ID() As Long<br />        Get<br />            Return _id<br />        End Get<br />        Set(ByVal value As Long)<br />            _id = value<br />        End Set<br />    End Property<br />    Property Nome() As String<br />        Get<br />            Return _nome<br />        End Get<br />        Set(ByVal value As String)<br />            _nome = value<br />        End Set<br />    End Property<br />    Property Email() As String<br />        Get<br />            Return _email<br />        End Get<br />        Set(ByVal value As String)<br />            _email = value<br />        End Set<br />    End Property<br />End Class

O código
define 3 membros e 2 propriedades para a classe Aluno que
representa um aluno com id, nome e email.

Agora só resta criar o código no
arquivo code-behind Default.aspx.vb para acessar o banco de dados,
obter os registros e gerar a lista genérica usando a classe
Aluno como tipo.

Abra o arquivo code-behind
Default.aspx.vb e inclua o código abaixo:

Imports usados:

Imports
System.Data
Imports System.Data.SqlClient

O método getAlunos() que acessa o banco de dados e gera uma lista
contendo uma coleção de objetos do tipo Aluno:

  Private Function getAlunos() As List(Of Aluno)<br /><br /> Dim<br />strConn As String = "Data<br />Source=.\SQLEXPRESS;AttachDbFilename=C:\_aspn\listaAlunosGenerics\App_Data\Escola.mdf;Integrated<br />Security=True;User Instance=True"<br />        Dim sql As String = "Select * from Alunos"<br /> Dim listaAlunos As List(Of Aluno) = New List(Of Aluno)<br />        Dim con As SqlConnection = New SqlConnection(strConn)<br /><br />        Try<br />            Dim cmd As SqlCommand = New SqlCommand(sql, con)<br />            con.Open()<br />            Dim dr As SqlDataReader = cmd.ExecuteReader<br />            While (dr.Read)<br />                Dim aluno As New Aluno<br />                aluno.ID = dr("id")<br />                aluno.Nome = dr("nome")<br />                aluno.Email = dr("email")<br />                listaAlunos.Add(aluno)<br />            End While<br />            Return listaAlunos<br />        Catch<br />            Throw New Exception("Erro ao gerar lista de alunos")<br />        Finally<br />            con.Close()<br />        End Try<br />    End Function

No evento Load da página
Default.aspx inclua o código que irá usar a função
getAlunos():

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load<br />        gdvAlunos.DataSource = getAlunos()<br />        gdvAlunos.DataBind()<br />    End Sub

Executando a página iremos obter o
seguinte resultado:

Mas afinal qual a vantagem? Ora bolas, com
Generics estamos trabalhando com objetos fortemente tipados em lista de
coleções de objetos e, ao invés de passar um dataset ou datatable, estamos
trafegando objetos.

Pegue os projetos completos aqui:
UsandoGenerics.zip (VB .NET) 
listaAlunosGenerics.zip (ASP .NET)

Eu sei, é apenas VB .NET e Generics, mas eu gosto…

é referência em Visual Basic no Brasil e autor dos livros "Aprenda Rápido: ASP" e "ASP, ADO e Banco de Dados na Internet". Mantenedor do site macoratti.net.

Ver perfil