Neste artigo, quero compartilhar uma experiência que tive sobre trabalhar com estruturas geréricas dinamicamente. A necessidade era de extender um ComboBox e implementar um método de pesquisa genérico, onde o ComboBox iria realizar uma pesquisa na tabela do tipo do objeto, passado como parâmetro de configuração para o ComboBoxSearch, nome que demos ao novo componente. Quero apenas deixar claro que o intuito deste post, não é criar o componente ComboBox extendido, mas sim mostrar como podemos fazer uso de rotinas genéricas e usar este recurso de forma dinâmica, em runtime.

Trabalhar com estruturas genéricas, é algo quase que de rotina hoje, tendo em vista a facilidade de casts, leitura dos dados das listas genéricas, flexibilidade de criação de classes genéricas. Porém, utilizar essas estruturas genéricas, de maneira dinâmica, não é algo que fazemos a todo momento. Contudo, se faz importante tomarmos conhecimento da solução.

Vamos abrir o VS2010!

Criaremos uma aplicação windows forms, sete o título (Propriedade Text do formulário) para Generic in Runtime. Adicione dois botões e altere a propriedadeName para btnInstanciar e btnInstanciarGenerico e clique 2x para adicionarmos o evento em cada botão. Após ter criado e configurado o projeto, iremos criar as seguintes classes com suas propriedades, configurações e métodos:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericInRuntime
{
public class ValueObject
{
public Int32 Id { get; set; }
public String Mensagem { get; set; }
}
}

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericInRuntime
{
public class Pessoa : ValueObject
{
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GenericInRuntime
{
public class PesquisaGenerica<T> where T : ValueObject
{
public void ExibirMensagem(T objeto)
{
MessageBox.Show(“Id: ” + objeto.Id.ToString() + ” – Mensagem: ” + objeto.Mensagem);
}

public void ExibirMensagem2<T>()
{
Type tipo = typeof(T);

MessageBox.Show(“Chamada ao Método Genérico. Nome do Tipo Genérico: ” + tipo.Name);
}
}
}

Com as classes criadas e configuradas, com suas propriedades e métodos. Vamos explicar agora o porque de cada uso genérico:

A criação da classe PesquisaGenerica<T> recebe qualquer classe, porém colocamos uma condição nesta classe, onde as classes passadas como parâmetros genérico, tem que herdar de ValueObject. Essa é a condição que precisamos para passar qualquer tipo de classe para nossa classe dePesquisaGenerica. No método ExibirMensagem, estamos fazendo uso do tipo genérico T da nossa classe de pesquisa, para informar ao método que o objeto que será passado como parâmetro, será do mesmo tipo da classe de Pesquisa. Como nossa classe ValueObject possui essas duas propriedades: Id e Mensagem, então qualquer classe que herdar dela, também terá essas acesso a essas propriedades.

Agora com nossa estrutura de classes criada. Vamos começar a parte interessante da brincadeira. Criar as classes Dinamicamente, utilizando Reflection com Generics.

Abaixo, teremos os códigos para os dois botões que temos no nosso formulário:

private void btnInstanciar_Click(object sender, EventArgs e)
{
object objeto = null;
object objetoParametro = null;
Type tipoGenerico = null;
Type[] parametrosConstrutor = null;
Type classeConstruida = null;

try
{
tipoGenerico = typeof(PesquisaGenerica<>);
parametrosConstrutor = new[] { typeof(Pessoa) };
classeConstruida = tipoGenerico.MakeGenericType(parametrosConstrutor);

MethodInfo mi = classeConstruida.GetMethod("ExibirMensagem", new Type[] { typeof(Pessoa) });

objeto = Activator.CreateInstance(classeConstruida);
objetoParametro = Activator.CreateInstance(typeof(Pessoa));

((Pessoa)objetoParametro).Id = 1;
((Pessoa)objetoParametro).Mensagem = "Execução de Método de Classe Genérica em Runtime";

mi.Invoke(objeto, new object[] { objetoParametro });
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.Message);
}
}

Neste evento temos, primeiramente, a recuperação do tipo Genérico. Sim, é exatamente desta forma que obtemos o tipo de uma classe Genérica. Como mostrado no código abaixo:

tipoGenerico = typeof(PesquisaGenerica<>);

Logo em seguida, estamos configurando um array de objetos que determinará qual será o parâmetro genérico que iremos passar para a nossa classe PesquisaGenerica<T>:

parametrosConstrutor = new[] { typeof(Pessoa) };

Para instanciarmos uma classe genérica, temos que fazer uso do métodoMakeGenericType, como no código abaixo:

classeConstruida = tipoGenerico.MakeGenericType(parametrosConstrutor);

Para obtermos o método que queremos da classe em runtime, temos que fazer uso do método GetMethod, mas como sabemos que o método recebe um parâmetro que é um objeto do tipo T, ou seja, é do mesmo tipo que a classe PesquisaGenerica será configurada. Então, estamos informando que o métod que estamos querendo executar, tem um parâmetro que é do tipo Pessoa:

MethodInfo mi = classeConstruida.GetMethod(“ExibirMensagem”, new Type[] { typeof(Pessoa) });

Agora estamos criando, instanciando os objetos que farão parte do uso do método em runtime:

objeto = Activator.CreateInstance(classeConstruida);
objetoParametro = Activator.CreateInstance(typeof(Pessoa));

E por fim, executamos o método, passando como parâmetro uma instância de um objeto do tipo Pessoa:

mi.Invoke(objeto, new object[] { objetoParametro });

Agora iremos mostrar como chamaremos o método genérico da nossa classe PesquisaGenerica, apenas como ressalva, o que mudará será apenas uma chamada a mais ao método MakeGenericMethod e não iremos passar nenhum parâmetro ao Método, apenas iremos tipar o Método, como mostrado no código abaixo:

private void btnInstanciarGenerico_Click(object sender, EventArgs e)
{
object objeto = null;
Type tipoGenerico = null;
Type[] parametrosConstrutor = null;
Type classeConstruida = null;

try
{
tipoGenerico = typeof(PesquisaGenerica<>);
parametrosConstrutor = new[] { typeof(Pessoa) };
classeConstruida = tipoGenerico.MakeGenericType(parametrosConstrutor);

MethodInfo mi = classeConstruida.GetMethod("ExibirMensagem2", new Type[] { });
MethodInfo miConstructed = mi.MakeGenericMethod(parametrosConstrutor);

objeto = Activator.CreateInstance(classeConstruida);

miConstructed.Invoke(objeto, null);
}
catch (Exception ex)
{
MessageBox.Show("Erro: " + ex.Message);
}
}

O que está em negrito e sublinhado, é o que muda para o código do primeiro evento para este segundo evento. Chamadas á métodos de maneira dinâmica é um excercício bastante interessante para sabermos como funciona, por trás dos bastidores, a estrutura de classes, construtores, parâmetros e métodos Genéricos.

O recurso de programação utilizando Generics, nos dá a flexbilidade de construirmos estruturas que possam receber tipos diversos de classes de domínio, no nosso exemplo, e trabalhar sobre suas informações. Contudo, o dinamismo que encontramos utilizando Reflection, é algo que ajudou bastante aos frameworks .NET a evoluirem e se aperfeiçoarem.

Para aprofundar-se no assunto desse tema entre na comunidade C#

Exibições: 1997

Comentar

Você precisa ser um membro de DevBrasil para adicionar comentários!

Entrar em DevBrasil

© 2018   Criado por Ramon Durães.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço