Criando List dinamicamente a partir de Select, com Reflection
Leonel Fraga de Oliveira 13/05/2009 00:00

Finalizando a série Reflection na Prática: Uso na Classe de Conexão, mostro a vocês como criar um List<> de uma classe que implementa uma tabela do banco de dados a partir de um comando Select.

Usamos List<> geralmente para poder iterar com várias instâncias de um objeto, ou para popular uma lista (grids, etc), e sendo assim fica mais simples de trabalhar os dados em uma aplicação.

Vamos ver agora o método CreateList() da classe Conexão:

 protected object CreateList(Type contentType, Type ListType, string isql, bool isqlHaveParams)
 {
     object list = Activator.CreateInstance(ListType);
     DataTable dt = getTable(isql, isqlHaveParams);
     foreach (DataRow r in dt.Rows)
     {
         object item = Activator.CreateInstance(contentType);
         foreach (DataColumn dc in dt.Columns)
         {
             FieldInfo fiItens = contentType.GetField("_" + dc.ColumnName.ToUpper(), BindingFlags.NonPublic | BindingFlags.Instance);
             if (r[dc.ColumnName] != DBNull.Value)
             {
                 fiItens.SetValue(item, ConverterDB2Obj(r[dc.ColumnName], fiItens.FieldType));
             }
         }
         ListType.InvokeMember("Add", BindingFlags.InvokeMethod, null, list, new object[] { item });
     }
     return list;
 }

Este método é o mais curto de todos os outros mostrados, porém ele tem um conceito a mais: criação de objetos em tempo de execução.

Este método recebe como parâmetros o tipo base de cada item da lista, o tipo da lista em si, a instrução SQL e um indicador de parametrização desta instrução SQL.

A classe de cada tipo da lista deve ter as suas variáveis privadas nomeadas segundo a convenção do método Select(), e os campos informados na instrução select sm “isql” são os que serão atribuídos em cada propriedade de cada item do list.

Primeiramente, criamos uma instância do List<> que iremos retornar, porém não podemos fazer isso de forma hardcoded, pois como este método é genérico, serve para List<> de qualquer tipo.

Para contornar isso, criaremos este objeto em tempo de execução, e para isso utilizamos o método Activator.CreateInstance(), do namespace System.Runtime.Remoting, sendo que a classe Activator serve exatamente para esta criação de objetos em tempo de execução (runtime).

O método CreateInstance() requer como parâmetro na sobrecarga que utilizamos o tipo de objeto a ser criado, sendo o tipo no parâmetro ListType, que é o tipo do List<> que iremos criar será passado como esse parâmetro. Guardamos este objeto na variável “list”, do tipo object.

Em seguida, utilizamos o método getTable da classe Conexão, passando a instrução SQL para pegar os dados e guardamos no DataTable “dt”.

Com um laço foreach, percorremos cada registro do DataTable.

Dentro deste laço, criamos, utilizando novamente o método Activator.CreateInstance() uma instância do item da lista, cuja classe está no parâmetro “contentType”.

Aqui um parêntese: O que aconteceria se criássemos esta instância FORA do laço foreach, hein? ;-)

Agora faremos um outro laço foreach, agora para iterar sobre as colunas deste registro que estamos trabalhando. Guardamos na variável fiItens, do tipo FieldInfo, as informações sobre a variável privada associada àquele campo, com o método GetField() da variável “contentType”.

Se o campo não estiver nulo, atribuiremos este valor na propriedade utilizando o método SetValue() do FieldInfo “fiItens”, que recebe como parâmetro o item que instanciamos acima e o valor com uma rotina de conversão aplicada (ver os outros artigos desta série para entender melhor).

Atribuídos todos os campos, chamaremos o método Add() do List<> de uma forma diferente: Através do método InvokeMember da classe Type, que no nosso caso é representado pela variável “ListType”.

Ele recebe como parâmetros o nome do método, no nosso caso Add, o Binding Flag, que no nosso caso é BindingFlags.InvokeMethod, o binder padrão, que pode ser null, o objeto a sofrer a execução do método e um array de object que representa a lista de parâmetros do método a ser executado.

No nosso caso, criamos um array de object com apenas um elemento, cujo valor é a variável item, que é o item da lista que iremos inserir.

Iterados todos os registros, saímos do primeiro laço e retornamos o List<> na forma de object.

Veja como utilizar este método:

 private List ListaGenerica()
 {
     List l = new List();
     return (List)CreateList(this.GetType(), l.GetType(), _SearchSQL, CountSQLParams() > 0);
 }
  
 public static List ListarTodos()
 {
     TTpFormaContato fc = new TTpFormaContato();
     fc._SearchSQL = "select * from TP_FORMA_CONTATO";
     fc.ClearSQLParams();
     return fc.ListaGenerica();
 }

Este trecho foi retirado do Simple PIM, o exemplo da nova Classe de Conexão, e de início criamos um objeto List para poder usar seu método GetType() no método CreateList().

Para utilizar efetivamente o list retornado, fazemos um typecast para o tipo base desejado (o que instanciamos acima).

Enfim, chegamos ao final da série Reflection na Prática: Uso na Classe de Conexão e vimos como o Reflection pode fazer a gente economizar código :-)

Um abraço!

Leonel Fraga de Oliveira Leonel Fraga de Oliveira é formado em Processamento de Dados na Faculdade de Tecnologia de São Paulo (FATEC-SP - 2002) e anteriormente em Técnico em Eletrônica, pela ETE Professor Aprígio Gonzaga (lá em 1999).
Atualmente trabalha como Analista de Sistemas na Prefeitura Municipal de São Caetano do Sul - SP
Tem como hobbies DJing (também trabalha como DJ freelancer) e ciclismo, além da manutenção dos sites NeoMatrix Light e NeoMatrix Tech.
Gosta de música eletrônica, tecnologia, cinema (super fã de Jornada nas Estrelas), gastronomia e outras coisas mais.


Compartilhe nas redes sociais

   

Deixe seu comentário

comments powered by Disqus