VB .NET - Reflection e Metadata
A maioria dos programas são escritos para trabalhar com dados. Eles em geral, lêem, escrevem, manipulam e exibem dados. (Gráficos são um exemplo típico de programas desse tipo). |
Os tipos que você, como o programador, criar e usar são projetados para estes fins, e é você, em tempo de projeto, que deve compreender as características dos tipos que você usa.
Metadado
Para alguns tipos de programas, no entanto, os dados que eles manipulam não são números, textos ou gráficos mas são as informações sobre programas e tipos de programa. Essas informações são conhecidas como metadados.(Uma informação sobre a informação)
Em uma metáfora podemos pensar em Metadados como sendo o sangue da plataforma. NET. Muitos dos recursos que usamos todos os dias durante o tempo de projeto, durante o tempo de compilação, e durante o tempo de execução, se baseiam na presença de metadados. Os Metadados permitem a um Assembly e os tipos dentro do Assembly se auto-descreverem.
Assim , os metadados são informações sobre os dados, ou seja, informações sobre os tipos, o código, assembly e assim por diante - que é armazenada junto com seu programa.
Podemos adicionar metadados em seu código através dos atributos.
Atributos
Os Atributos são um mecanismo para a adição de metadados, tais como instruções do compilador e outros dados sobre seus dados, métodos e classes, para o próprio programa. Atributos são inseridos nos metadados e são visíveis através ILDasm e outras ferramentas para leitura de metadados.
Um atributo é um objeto que representa os dados que você deseja associar com um elemento no seu programa. O elemento ao qual você anexa um atributo é conhecido como o target (alvo) desse atributo.
Por exemplo, o atributo: [NoIDispatch]
Está associado a uma classe ou uma interface para indicar que a classe alvo deve derivar de IUnknown, em vez de IDispatch, ao exportar para COM.
Atributos podem ser de dois tipos: intrínsecos e personalizado.
Se você procurar na CLR, você vai encontrar um grande número de atributos. Alguns atributos são aplicados a uma assembly, outros a uma classe ou interface, e alguns, como o [WebMethod], a membros da classe. A seguir temos os principais os alvos de atributos:
Nome do Membro | Uso |
---|---|
All |
Aplicado a qualquer um dos seguintes elementos: assembly, class, class member, delegate, enum, event, field, interface, method, module, parameter, property, return value, ou struct |
Assembly |
Aplicado ao próprio assembly |
Class |
Aplicado a instância de classes |
ClassMembers |
Aplicado a classes, structs, enums, constructors, methods, properties, fields, events, delegates, e interfaces |
Constructor |
Aplicado a um dado constructor |
Delegate |
Aplicado a método delegado |
Enum |
Aplicado a uma enumeração (enumeration) |
Event |
Aplicado a um evento (event) |
Field |
Aplicado a um campo (field) |
Interface |
Aplicado a uma interface |
Method |
Aplicado a um método |
Module |
Aplicado a um único módulo |
Parameter |
Aplicado a um parâmetro de um método |
Property |
Aplicado a uma
propriedade (get e
set ,
se implementado) |
ReturnValue |
Aplicado a um valor retornado |
Struct |
Aplicado a um struct |
Aplicando atributos
Você pode aplicar atributos para seus alvos, colocando-os entre colchetes imediatamente antes do item de destino. Você pode combinar atributos quer por empilhamento um sobre o outro:
[assembly: AssemblyDelaySign
(false)]
[assembly: AssemblyKeyFile ("\\KeyFile.snk.")]
ou separando os atributos com vírgulas:
[assembly: AssemblyDelaySign (false), assembly: AssemblyKeyFile ("\\KeyFile.snk.")]
Reflection
Um programa pode olhar para os metadados de outros conjuntos ou de si mesmo, enquanto ele está executando. Quando um programa em execução olha para seus próprios metadados, ou de outros programas, a ação é chamada de Reflection.
Dessa forma, Reflection é o processo pelo qual um programa pode ler seus próprios metadados. Um programa que faz Reflection sobre si mesmo, extrai metadados de sua montagem e usa estes metadados ou para informar ao usuário ou para modificar o seu próprio comportamento.
Reflection é então a capacidade de ler metadados em tempo de execução. Usando a reflexão (Reflection), é possível descobrir os métodos, propriedades e eventos de um tipo, e então invocá-los dinamicamente. Usando Reflection podemos também criar novos tipos em tempo de execução.
Um Object Browser (Navegador de objetos) é um exemplo de um programa que exibe metadados. Ele pode ler assemblies e exibir os tipos que eles contêm, juntamente com todas as características e os membros.
Reflection geralmente começa com uma chamada para um método presente em todos os objetos do framework NET: GetType.
O método GetType é um membro da classe System.Object, e o método retorna uma instância de System.Type, e System.Type é a porta de entrada para os metadados.
A classe System.Type é na verdade derivada de outra classe importante de reflexão: a classe MemeberInfo do namespace System.Reflection.
A classe MemberInfo é uma classe base para muitas outras classes que descrevem as propriedades e métodos de um objeto, incluindo FieldInfo, MethodInfo, ConstructorInfo, ParameterInfo e EventInfo entre outros.
Como você pode suspeitar pelos seus nomes, você pode usar essas classes para inspecionar os diferentes aspectos de um objeto em tempo de execução.
Compreendendo Metadados de Assemblies
Quando você cria um executável com o Visual Basic, você constrói um assembly .NET. Um assembly é basicamente um recipiente de metadados e código. Os metadados são informações que a CLR usa para carregar e executar corretamente o assembly.
A Figura abaixo representa como um assembly é estruturado:
Observe que tipos dentro de um assembly podem ser agrupados em vários módulos. Um módulo é um container de tipos enquanto um assembly é um recipiente de módulos. Com reflection você pode inspecionar metadados e o código de um assembly usando código do Visual Basic, incluindo informações do assembly.
Obs: Quando se fala sobre assemblies, normalmente nos referimos a arquivos executáveis únicos. Assemblies podem ser compostos de vários arquivos vinculados; tenha em mente que os metadados de um assembly precisam residir apenas no assembly principal. Este é um caso especial e não pode ser realizado com o Visual Studio (você deve usar manualmente o MSBuild).
Praticando um pouco - preparando um Assembly de teste
Antes de mostrar as capacidades de Reflection, uma boa idéia é preparar um exemplo de código apropriado.
Primeiro, crie um novo projeto de biblioteca de classe com o nome Pessoa. O objetivo da biblioteca é expor uma implementação especial da classe Pessoa, com interfaces e implementações de enumerações para uma melhor demonstração de Reflection.
Abra o Visual Basic 2010 Express Edition e no menu File selecione New Project e a seguir escolha o template Class Library e informe o nome Pessoa e clique em OK;
Altere o nome da classe Class1.vb criada por padrão no projeto para Pessoa.vb e a seguir digite o código exibido a seguir :
Imports System.Text Public Enum Generos Masculino = 0 Feminino = 1 End Enum Public Interface IPessoa Property Nome As String Property Sobrenome As String Property Idade As Integer Property Genero As Generos Event InstanciaCriada() Function CriarNomeCompleto() As String End Interface Public Class Pessoa Implements IPessoa Public Property Nome As String Implements IPessoa.Nome Public Property Genero As Generos Implements IPessoa.Genero Public Property Sobrenome As String Implements IPessoa.Sobrenome Public Property Idade As Integer Implements IPessoa.Idade Public Event InstanciaCriada() Implements IPessoa.InstanciaCriada Public Overridable Function CriarNomeCompleto() As String _ Implements IPessoa.CriarNomeCompleto Dim nomeCompleto As New StringBuilder nomeCompleto.Append(Sobrenome) nomeCompleto.Append(" ") nomeCompleto.Append(Nome) nomeCompleto.Append(", ") nomeCompleto.Append(Genero.ToString) nomeCompleto.Append(", de idade ") nomeCompleto.Append(Idade.ToString) Return nomeCompleto.ToString End Function End Class |
|
Dê um Build no projeto (menu Debug-> Build Pessoa), e em seguida, adicione um projeto Console à solução atual através do menu File-> Add -> New Project, com o nome TesteReflection;
Por fim, adicione uma referência para a biblioteca de classes Pessoa de modo que, apenas para fins de demonstração, você possa carregar o assembly para a reflection, sem especificar o caminho completo.
Para isso no clique com o botão direito sobre o projeto console TesteReflection e selecione Add Reference e a seguir na janela Add Reference selecione o projeto Pessoa e clique em OK:
Obtendo informações de um Assembly
Podemos obter informações dos metadados de um assembly criando uma instância da classe System.Reflection.Assembly. Esta classe fornece membros estáticos e de instância para acessar informações de um assembly. Na tabela abaixo temos os métodos que em geral são usados para carregar um assembly e obter informações sobre seus metadados:
Método | Descrição |
---|---|
GetExecutingAssembly | Retorna a instância do assembly atual |
GetEntryAssembly | Retorna a instância do assembly que executa o processo atual |
Load | Carrega o assembly especificado no domínio da aplicação atual |
LoadFile | Carrega o assembly especificado a partir de um caminho definido |
LoadFrom | Carrega o assembly especificado no domínio da aplicação atual dado o caminho definido |
ReflectionOnlyLoad | Igual a Load , mas permite somente a inspeção Reflection e não a execução de código |
ReflectionOnlyLoadFrom | Igual a LoadFrom, mas permite somente a inspeção Reflection e não a execução de código |
Quando você obtêm a instância do assembly o qual você deseja inspecionar você pode acessar a informação através de propriedades conforme mostrado no código a seguir que deve ser colocada no módulo do projeto console TesteReflection:
Altere o nome do módulo do projeto console TesteReflection de Module1.vb para getAssemblyInfo.vb e a seguir inclua o código abaixo no módulo:
Imports System.Reflection Module getAssemblyInfo Sub Main() 'Infere o namespace System.Reflection.Assembly Dim asm = Assembly.ReflectionOnlyLoadFrom("Pessoa.dll") With asm 'Obtém o nome completo do assembly com versão e cultura Console.WriteLine("Nome do Assembly:") Console.WriteLine(.FullName) 'Obtém informação se o assembly e confiável (trusted) Console.WriteLine("É confiável: {0}", .IsFullyTrusted) 'Obtém o ponto de entrada do assembly; se vazio o construtor 'é o ponto de entrada Console.WriteLine("O método ponto de entrada é: {0}", .EntryPoint) 'Obtém a versão da plataforma .NET no qual o assembly foi construído Console.WriteLine("Versão do Runtime: {0}", .ImageRuntimeVersion) 'Informa se o assembly foi carregado do GAC Console.WriteLine("Carregado a partir do GAC: {0}", .GlobalAssemblyCache) 'Obtém a localização do assembly Console.WriteLine("Caminho do Assembly : {0}", .Location) 'Obtém um array de módulos carregado pelo assembly Console.WriteLine("Modulos carregados: ") For Each item As System.Reflection.Module In .GetLoadedModules Console.WriteLine(" {0}", item.Name) Next End With Console.ReadLine() End Sub End Module |
|
Observe como o código utilizar o método ReflectionOnlyLoadFrom para permitir somente a inspeção se poder executar código. Ao executar o projeto acima iremos obter:
Obs: Para poder executar o projeto TesteReflection clique sobre o mesmo com o botão direito do mouse e selecione Set as Startup Project.
- Observe que o número da versão RTM da plataforma .NET obtido: v4.0.30319
- O método Assembly.GetModules retorna um array dos módulos carregados pela instância do assembly : Pessoa.dll
Existem outros métodos interessantes que poderíamos ter usado como:
- GetExportedTypes
o qual retorna um array dos tipos vísiveis publicamente ;
- GetFiles que retorna um array de objetos FileStream
representando um arquivo no recurso do assembly
Até o momento estão usando Reflection para obter informação do assembly no primeiro nível o próximo passo é realizar a inspeção de tipos,mas isso é assunto para outro artigo, aguarde...
Pegue o projeto completo aqui: Pessoa_Reflection.zip
"E a ninguém na terra chameis vosso pai,
porque um só é o vosso Pai, o qual esta nos céus."
"Nem vos chameis mestres, porque um só é o vosso Mestre, que é o Cristo." Mateus
23:9-10
Referências: