.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 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:

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 ordernar, 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
        'Inclui nomes na lista
        listaAlunos.Add("Macoratti")
        listaAlunos.Add("Jefferson")
        listaAlunos.Add("Jessica")
        listaAlunos.Add("Janice")
        listaAlunos.Add("Bianca")
        listaAlunos.Add("Yuri")
        listaAlunos.Add("Larissa")
        listaAlunos.Add("Larissa")
        listaAlunos.Add("Madalena")
        listaAlunos.Add("Marcia")
        listaAlunos.Add("Carlos")
    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
        Dim nomeAluno As String = txtNome.Text
        ' Encontrou o nome
        If listaAlunos.Contains(nomeAluno) Then
            ' Exibe o nome e o total de nomes
            Dim msg As String = "{0} foi encontrado em uma relação de  {1} nome(s)"
            lstAlunos.Items.Add(String.Format(msg, nomeAluno, listaAlunos.Count))
        Else
            ' Não encontrou nome na lista
            lstAlunos.Items.Add("Nome não encontrado na lista!")
        End If
    End Sub

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

Para listar o conteúdo da lista incluimos 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
        For i = 0 To listaAlunos.Count - 1
            lstAlunos.Items.Add(listaAlunos(i))
        Next
  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
      lstAlunos.Items.Add(nome)
Next
Usando o loop For Each percorremos a lista e exibimos o nome.

ou ainda:

    Dim atual As String
    Dim en As IEnumerator(Of String) = listaAlunos.GetEnumerator()
    While (en.MoveNext())
         atual = en.Current
        lstAlunos.Items.Add(atual)
    End While
Usando o GetEnumerator() que é um função da interface
IEnumerable obtemos um enumerator com 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
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 As String
listaAlunos.Sort()
Dim en As IEnumerator(Of String) = listaAlunos.GetEnumerator()
While (en.MoveNext())
    atual = en.Current.ToUpper()
    lstAlunos.Items.Add(atual)
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 dados 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é 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:

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;

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

Public Class Aluno
    Dim _id As Long
    Dim _nome As String
    Dim _email As String

    ReadOnly Property ID() As Long
        Get
            Return _id
        End Get
        Set(ByVal value As Long)
            _id = value
        End Set
    End Property
    Property Nome() As String
        Get
            Return _nome
        End Get
        Set(ByVal value As String)
            _nome = value
        End Set
    End Property
    Property Email() As String
        Get
            Return _email
        End Get
        Set(ByVal value As String)
            _email = value
        End Set
    End Property
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 acesso o banco de dados e gera uma lista contendo uma coleção de objetos do tipo Aluno:

  Private Function getAlunos() As List(Of Aluno)

        Dim strConn As String = "Data Source=.\SQLEXPRESS;AttachDbFilename=C:\_aspn\listaAlunosGenerics\App_Data\Escola.mdf;Integrated Security=True;User Instance=True"
        Dim sql As String = "Select * from Alunos"
        Dim listaAlunos As List(Of Aluno) = New List(Of Aluno)
        Dim con As SqlConnection = New SqlConnection(strConn)

        Try
            Dim cmd As SqlCommand = New SqlCommand(sql, con)
            con.Open()
            Dim dr As SqlDataReader = cmd.ExecuteReader
            While (dr.Read)
                Dim aluno As New Aluno
                aluno.ID = dr("id")
                aluno.Nome = dr("nome")
                aluno.Email = dr("email")
                listaAlunos.Add(aluno)
            End While
            Return listaAlunos
        Catch
            Throw New Exception("Erro ao gerar lista de alunos")
        Finally
            con.Close()
        End Try
    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
        gdvAlunos.DataSource = getAlunos()
        gdvAlunos.DataBind()
    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ências:


José Carlos Macoratti