Atenção: esse artigo tem um vídeo complementar. Clique e assista!

De que se trata o artigo

O artigo demonstra como converter os dados que foram carregados para uma lista genérica em um objeto do tipo DataTable. A principal finalidade é possibilitar que estes dados possam ser facilmente ordenados ao se usar um controle DataGridView de aplicações do tipo Windows Forms, mas também, demonstrar alguns recursos de Reflection para se descobrir dinamicamente a estrutura de dados das classes.


Para que serve

Reflection é um recurso poderoso das linguagens de programação e do framework .Net que permite ao desenvolvedor criar aplicações mais dinâmicas e adaptáveis. Ao entrar em contato com a tarefa de conversão de uma coleção genérica para outro tipo de dado vários elementos da programação com a linguagem C# são explicados permitindo que em projetos futuros, o desenvolvedor possa ter um ponto de referência para seu uso.


Em que situação o tema é útil

O tema vai ajudar não só a resolver problemas de ordenação quando estiver carregando dados em um controle DataGridView, mas também, permitir um conhecimento maior dos recursos para o trabalho com consultas, tabelas de bancos de dados e Reflection.

Conversão de List<T> para DataTable

Ao preencher o controle DataGridView que é usado nas aplicações Windows usando uma lista genérica, ao clicar nos cabeçalhos da coluna com o mouse, eles não têm o comportamento esperado de autoordenação. Embora seja possível fazer isto implementando a interface IComparable para a classe que originou a lista, isto pode ser complicado de se fazer. Uma saída é converter estes dados para um objeto do tipo DataTable. Dentre as várias formas de se fazer isto a mais indicada é usando Reflection para que qualquer classe possa ser convertida, desde que seguidas algumas observações na sua geração. Esta tarefa será demonstrada neste artigo usando uma aplicação Windows Forms.

As pessoas usam programas de computador para acessar seus dados de maneira organizada. Vendas, agendas, contabilidade, estatística e muitas outras áreas de atividades humanas se beneficiam das facilidades proporcionadas pelos programas de computador. Os programas desenvolvidos em plataformas gráficas como o Windows agilizam o trabalho tanto para o usuário como para o desenvolvedor desses programas. No framework .Net isto é particularmente observado na maneira como os controles visuais são facilmente preenchidos com dados oriundos das mais diversas fontes, principalmente bancos de dados.

Recentemente o mapeamento objeto-relacional, através do qual se procura quebrar a distância existente entre as linguagens de programação e a maneira como os dados são armazenados e manipulados nos bancos, evoluiu bastante e recursos como Entity Framework, LINQ (Language INtegrated Query) e facilidades para manipulação de coleções de objetos na memória se tornaram cada vez mais comuns. Estes recursos, no entanto, exigem mais do desenvolvedor que, antes, usava os geradores de código automático.

Nota: Estes recursos ainda existem. Considerando o DataSet Designer do Visual Studio, através do qual é bem simples fazer mapeamento das tabelas de um banco de dados para uso no preenchimento de controles visuais ou para se trabalhar no código de maneira mais organizada. No entanto, muito do código gerado é desnecessário e muitas vezes penaliza o desempenho da aplicação final.

Termos como S.O.L.I.D., Entity Framework, Code First, entre outros, vêm tomando conta do vocabulário dos programadores que, num surpreendente retorno às origens, voltaram a meter a mão na massa tendo de voltar a escrever grande quantidade de código para criar programas ágeis e bem feitos. Isso tudo tem um reflexo quando além da agilidade e boa arquitetura a aplicação precisa ser amigável ao usuário final.

Existem alguns reflexos negativos quando, por exemplo, usamos uma coleção de objetos baseados em uma lista genérica. O controle DataGridView muito popular nos programas Windows Forms possui a característica de permitir a ordenação automática de seu conteúdo ao se clicar em um cabeçalho de uma coluna. Mesmo existindo outros recursos interessantes deste controle, esta facilidade é perdida quando se usa uma lista genérica para preencher este controle.

Isto acontece porque, para que as colunas sejam automaticamente ordenadas é preciso código fazendo a ordenação dos dados e isto deve ser explicitamente implementado, ou seja, o desenvolvedor deve escrever código para esta tarefa.

Outra forma de se fazer isto é usar a classe DataTable para preencher o controle. Como esta possui a lógica necessária para fazer a ordenação e muitas tarefas da manipulação de dados, acaba sendo a melhor escolha para preenchimento rápido dos dados neste tipo de controle.

Porém, em muitos projetos os dados já são passados neste formato não sendo possível reescrever a camada de acesso de dados. Uma solução é obter os dados desta lista para preencher a classe DataTable. Para tanto é preciso conhecer a estrutura da classe que compõe a lista de dados e isto também pode ser feito com relativa facilidade dentro do .Net usando Reflection.

Reflection e a estrutura de objetos

Dentre as muitas funcionalidades obtidas com o uso de Reflection a principal é aquela que possibilita conhecer os elementos que compõem uma classe. Usando as classes das bibliotecas System.Type e System.Reflection o desenvolvedor pode ler os atributos, propriedades, campos, métodos e construtores das classes que fazem parte de qualquer assembly (executável ou class library) desenvolvido com as linguagens do framework .Net.

Isto é possível porque os assemblys são criados em uma linguagem chamada Common Runtime Language (CLR) e possuem uma estrutura que armazena os seus dados em uma tabela nestes arquivos, que por sua vez, podem ser lidos por outros programas também desenvolvidos no framework.

Nota do DevMan

Reflection não é uma exclusividade do .Net. É anterior ao mesmo, mas, com a CLR é implementado com muito mais facilidade dentro deste ambiente permitindo que programadores com poucos conhecimentos consigam obter produtividade ao lançar mão destas técnicas. Naturalmente que programas desenvolvidos em outras plataformas como os executáveis nativos para o Windows e outros sistemas operacionais permitem o Reflection usando outros tipos de recursos. Uma demonstração disto é que os programas do framework através do Interop podem consumir class librarys desenvolvidas em outras linguagens.

As principais classes para as tarefas de Reflection estão localizadas nas bibliotecas System.Reflection e System.Type. Entre as principais classes destacam-se as da Tabela 1.

Classe

Para que deve ser usada

Assembly

É através desta classe que recuperam informações sobre o assembly ou seja, dados do executável ou da class library. Usado para descobrir informações relevantes sobre o arquivo e também para fazer a carga dinâmica de um tipo e poder usar elementos deste tipo.

ConstrutctorInfo

Classe que recupera informações sobre o construtor de um determinado tipo.

FieldInfo

Usada para recuperar os metadados dos campos da classe. (Para ler as propriedades usA-se PropertyInfo).

MethodInfo

Obtém metadados sobre os métodos da classe (públicos, privados, estáticos, etc.).

PropertyInfo

Retorna informações sobre as propriedades da classe. É através desta classe que se pode descobrir o tipo da propriedade e ler ou escrever valores no mesmo.

Tabela 1. Principais classes da biblioteca System.Reflection

Nota: a principal diferença entre propriedades e campos (property e field) é que geralmente as propriedades implementam alguma lógica no armazenamento dos dados através dos assessores get/set. Já os campos simplesmente guardam os dados do tipo que foi definido.

...
Quer ler esse conteúdo completo? Tenha acesso completo