O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

quarta-feira, 13 de maio de 2009

Criando List<> dinamicamente a partir de Select, com Reflection

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:

   1: protected object CreateList(Type contentType, Type ListType, string isql, bool isqlHaveParams)
   2: {
   3:     object list = Activator.CreateInstance(ListType);
   4:     DataTable dt = getTable(isql, isqlHaveParams);
   5:     foreach (DataRow r in dt.Rows)
   6:     {
   7:         object item = Activator.CreateInstance(contentType);
   8:         foreach (DataColumn dc in dt.Columns)
   9:         {
  10:             FieldInfo fiItens = contentType.GetField("_" + dc.ColumnName.ToUpper(), BindingFlags.NonPublic | BindingFlags.Instance);
  11:             if (r[dc.ColumnName] != DBNull.Value)
  12:             {
  13:                 fiItens.SetValue(item, ConverterDB2Obj(r[dc.ColumnName], fiItens.FieldType));
  14:             }
  15:         }
  16:         ListType.InvokeMember("Add", BindingFlags.InvokeMethod, null, list, new object[] { item });
  17:     }
  18:     return list;
  19: }

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:

   1: private List<TTpFormaContato> ListaGenerica()
   2: {
   3:     List<TTpFormaContato> l = new List<TTpFormaContato>();
   4:     return (List<TTpFormaContato>)CreateList(this.GetType(), l.GetType(), _SearchSQL, CountSQLParams() > 0);
   5: }
   6:  
   7: public static List<TTpFormaContato> ListarTodos()
   8: {
   9:     TTpFormaContato fc = new TTpFormaContato();
  10:     fc._SearchSQL = "select * from TP_FORMA_CONTATO";
  11:     fc.ClearSQLParams();
  12:     return fc.ListaGenerica();
  13: }

Este trecho foi retirado do Simple PIM, o exemplo da nova Classe de Conexão, e de início criamos um objeto List<nome da classe> 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!

0 comentários:


Postar um comentário

Para tornar este artigo ainda mais interessante, escreva suas críticas (desde que construtivas e sem ofenças), elogios, sugestões, complementos, dúvidas, etc, etc, etc!!!

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO