Desenvolvimento - C#
Reflection - Utilizando Objetos dinamicamente
Este artigo ilustra a utlização de objetos através do Reflection.
por Anderson MeloReflection é uma funcionalidade do .NET Framework capaz de recuperar informações, ou melhor, recuperar metadados de Assemblies sendo possível então interrogar tipos, métodos, propriedades, variáveis locais, delegates, atributos etc. Além de interrogar Assemblies, o reflection oferece também mecanismos para criar código on fly e ainda a possibilidade de se criar um Assembly em tempo de execução, salvá-lo no disco e acessá-lo e utilizá-lo posteriormente.
Este artigo ilustra um cenário onde existe a necessidade de se utilizar um método localizado em um assembly, que por sua vez não pode ser adicionado como referência do projeto principal, por algum motivo qualquer. Dessa forma, o objeto que contém este método, será instanciado dinamicamente via reflection, possibilitando assim a utilização de seus recursos.
Primeiro será criado o Assembly que irá conter o método que será acessado via Reflection, é um projeto do tipo Class Library, que contém uma classe chamada PersonBLL. A classe por sua vez possui um construtor parameterless e um método que recebe e retorna uma string. A Listagem 1 mostra o conteúdo da classe PersonBLL.
using System; using System.Collections.Generic; using System.Text;
namespace PersonBLL { public class PersonBLL { public PersonBLL() { }
public new static string GetMessage(string userName) { if (!string.IsNullOrEmpty(userName)) return string.Concat("Hello user ", userName); else return string.Empty; } } } |
Listagem 1 – Conteúdo da classe PersonBLL.
Ao compilar este projeto, fique atento quanto à localização em que o Assembly foi gerado, esta informação será muito útil neste exemplo, basta visualizar na janela Output, como mostra a Figura 1.
|
Figura 1 – Output que indica onde o Assembly foi gerado.
Tendo em mãos o Assembly que será utilizado via Reflection, agora é necessário criar a aplicação que irá acessá-lo. Para isto, este artigo utiliza-se de uma aplicação Console.
Em uma situação normal, sem o uso de Reflection, os passos que devem ser tomados para chamar um método não estático são: Instanciar um objeto, normalmente via um Construtor, e finalmente chamar o método desejado suprindo os determinados parâmetros se for o caso. Utilizando o Reflection, os passos são os mesmos, apenas a forma em que estas tarefas são realizadas é que mudam.
A Listagem 2 mostra como o objeto é instanciado via Reflection, é necessário adicionar a diretiva using System.Reflection.
Assembly assembly = Assembly.LoadFrom(@"C:\Anderson\Microsoft.NET\Article\PersonBLL\PersonBLL\bin\Debug\PersonBLL.dll");
Type assemblyType = assembly.GetType("PersonBLL.PersonBLL");
Type[] ctorParameter = Type.EmptyTypes;
ConstructorInfo ctor = assemblyType.GetConstructor(ctorParameter);
object instance = ctor.Invoke(new object[] { }); |
Listagem 2 – Criando uma instância de um objeto com Reflection.
Observando a Listagem 2, um objeto Assembly é criado através do método estático LoadFrom, passando como parâmetro o caminho do assembly criado anteriormente. Após a criação do objeto que representa o assembly, recupera-se o tipo que se deseja utilizar, neste caso, é chamado o método GetType passando como parâmetro o nome completo (namespace + classe). O próximo passo então é encontrar o construtor e chamá-lo, isso é feito com o método GetConstructor, que neste caso é passado uma variável que representa um Array de Types vazio, para recuperar o construtor que não possui parâmetros. Com o construtor encontrado, a próxima tarefa é invocá-lo, através do método Invoke, que irá retornar uma instância do objeto desejado. Como no passo anterior foi recuperado um construtor parameterless, ao invocá-lo é passado um array de object vazio.
Após a fase de criação do objeto, é necessário recuperar o método que se deseja executar, e então finalmente executá-lo, a Listagem 3 ilustra estas ações.
MethodInfo method = instance.GetType().GetMethod("GetMessage");
if (method != null) { string message = method.Invoke(instance, new object[] { "Anderson Melo" }) as string;
Console.WriteLine("The method result is {0}", message); } else Console.WriteLine("Method not found"); |
Listagem 3 – recupera e executa o método.
Na listagem 3, é utilizado o método GetMethod passando como parâmetro o nome do método, que se de fato existir dentro daquele tipo será armazenado dentro do objeto MethodInfo, que por sua vez representa um método. Após este passo, é então novamente utilizado o método Invoke, só que desta vez do objeto do tipo MethodInfo. Desta vez, o Invoke recebe um object que representa a instancia do objeto que possui o método, e um segundo parâmetro que é um array de object, que representa os parâmetros do método, e irá retornar um object que será o retorno do método, que neste caso é uma string, completando dessa forma, a chamada do método.
A Listagem 4 apresenta todo o conteúdo da Console Application que utiliza o Reflection para chamar um método de um Assembly.
using System; using System.Collections.Generic; using System.Text; using System.Reflection;
namespace ReflectionApp { class Program { static void Main (string[] args) { Assembly assembly = Assembly.LoadFrom(@"C:\Anderson\Microsoft.NET\Article\PersonBLL\PersonBLL\bin\Debug\PersonBLL.dll");
Type assemblyType = assembly.GetType ("PersonBLL.PersonBLL");
Type[] ctorParameter = Type.EmptyTypes;
ConstructorInfo ctor = assemblyType.GetConstructor (ctorParameter);
object instance = ctor.Invoke(new object[] { });
MethodInfo method = instance.GetType() .GetMethod ("GetMessage");
if (method != null) { string message = method.Invoke(instance, new object[] { "Anderson Melo" }) as string;
Console.WriteLine("The method result is {0}", message); }
else Console.WriteLine("Method not found");
Console.ReadLine(); } } } |
Listagem 4 – Código da Console Application
O Reflection é uma poderosa ferramenta que possibilita utilizar objetos de maneira dinâmica bem como recuperar grande quantidade de informação sobre objetos, porém deve ser utilizada com bastante cuidado em relação à performance, que é um pouco piorada se comparada com a utilização normal de objetos.