O espaço chamado "System.Reflection"do Framework .NET nos permite dissecar uma Assembly (uma Assembly é um projeto) e saber por exemplo: qual é a lista de campos, propriedades ou métodos que contêm classes desta montagem (Assembly).
Vamos supor que nossos leitores têm um mínimo de conhecimento sobre a plataforma .NET e os WinForms. Além do mais, vamos tomá-los como base no nosso exemplo sobre o Framework.NET 3.5 com o IDE Microsoft Visual Studio 2008.
Abaixo, nossas escolhas para a criação do nosso projeto.
Começaremos por escolher um projeto do tipo "Windows Forms Application". Aqui, vemos a escolha do ". NET Framework 3.5".
Depois de criar o projeto, você encontrará um WinForms já adicionado "Form1".
Agora adicione uma classe ao seu projeto "Shift + Alt + c"
Na Classe1 adicionar os seguintes campos:
private string camposTeste1 = string.Empty; private string champsTest2 = string.Empty;
E as seguintes propriedades:
public string CamposTeste1 { get { return camposTeste1; } set { camposTeste1 = value; } } public string CamposTeste2 { get { return camposTeste2; } set { camposTeste2 = value; } }
E os seguintes métodos:
public string Method1() { return string.Empty; } public string Method2() { return string.Empty; }
Agora vá em Form1, adicione um botão, e insira o seguinte código em seu evento clique:
private void button1_Click(object sender, EventArgs e) { // Em primeiro lugar, fazemos uma chamada em curso de execução Assembly asm = Assembly.GetExecutingAssembly(); // Vamos escolher a classe Classe1 para dissecá-la, indo buscar seu tipo System.Type type = asm.GetType("Test.Class1"); // pedimos ao Tipo de nos retornar a lista dos campos que ele contém string strFields = "Lista dos fields : rn"; foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)) strFields += fi.Name + " : " + fi.FieldType.Name + ", "; // pedimos ao Tipo de nos retornar a lista dos métodos que ele contém string strMethods = "rnrn Lista dos métodos : rn"; foreach (MethodInfo mi in type.GetMethods()) strMethods += mi.Name + " : " + mi.ReturnType.Name + ", "; // pedimos ao Tipo de nos retornar a lista das propriedades que ele contém string strProperties = "rnrn Lista das propriedades: rn"; foreach (PropertyInfo pi in type.GetProperties()) strProperties += pi.Name + " : " + pi.PropertyType.Name + ", "; MessageBox.Show(strFields + strMethods + strProperties); }
Lembre-se de adicionar a seguinte declaração no seu formulário:
using System.Reflection;
Execute o seu projeto e pressione o botão do seu formulário: você verá uma lista dos campos, propriedades e métodos que contém a classe Class1. O mais importante é que todo o processo é desenvolvido de uma forma genérica, em nenhum caso, fomos obrigados a instanciar nossa classe e obter estas propriedades, esses campos ou esses métodos de uma forma convencional.
Suponhamos que utilizamos o Class1 como o apoio de dado para depois inserí-lo em um banco de dados e, queremos ter certeza de que na validação desta inserção, todas as propriedades do Class1, que são obrigatórias, terão um valor, só que queremos fazer esta verificação de forma genérica. Para isso, vamos utilizar o espaço de nome (namespace) "System.Reflection" e o espaço de nome "System.ComponentModel", que nos permitirá de adicionar dados estáticos à nossa classe a partir dos atributos.
Em seu Class1 adicione a seguinte instrução:
using System.ComponentModel;
E substitua as duas propriedades da sua classe pelas seguintes propriedades:
[Description("descrição dos camposTeste1")] public string CamposTeste1 { get { return camposTeste1; } set { camposTeste1 = value; } } [Description("descrição dos camposTeste 2"), Category("Mandatory")] public string CamposTeste2 { get { return camposTeste2; } set { camposTestet2 = value; } }
Você pode ver que adicionamos atributos às nossas propriedades: o atributo "Descrição" (Description] e o atributo "Categoria" (Category]. Agora, vamos supor que todas as propriedades que possuem um atributo "Categoria" com valor "Mandatory" devem, necessariamente, ter um valor diferente de zero.
A atribuição de atributos pode ser feita para as classes, propriedades, campos e métodos; em outro caso de uso, podemos criar o nosso próprio atributo (por exemplo: criar um atributo "Persistir"), que será distribuído às propriedades do uma classe e cujo valor servirá a identificar o campo em que o banco de dados vai inserir o valor de nossa propriedade, e a partir daí, poderemos gerar pedidos de inserção de maneira completamente automatizada.
Agora vá em Form1, adicione um botão, e insira o seguinte código em seu evento clique:
private void button2_Click(object sender, EventArgs e) { // Em primeiro lugar, fazemos uma chamada em curso de execução Assembly asm = Assembly.GetExecutingAssembly(); // Vamos escolher a classe Classe1 para dissecá-la, indo buscar seu tipo System.Type type = asm.GetType("Test.Class1"); // podemos utilizar a reflexão para instanciar uma classe object o = asm.CreateInstance("Test.Class1"); // podemos utilizar a reflexão para modificar o valor de uma propriedade PropertyInfo pi = type.GetProperty("ChampsTest1"); pi.SetValue(o, "novo valor", null); // podemos utilizar a reflexão para modificar o valor de uma propriedade pi = type.GetProperty("CamposTeste2"); pi.SetValue(o, null, null); // pedimos ao Tipo de nos retornar a lista das propriedades que ele contém string strVerification = string.Empty; foreach (PropertyInfo piv in type.GetProperties()) { // para cada propriedade verificamos se ela possui um atributo do tipo "Category" foreach(object oatt in piv.GetCustomAttributes(typeof(System.ComponentModel.CategoryAttribute),true)) { // se for o caso vamos buscar sua descrição no atributo "Description" // para poder formular o nosso alerta corretamente System.ComponentModel.CategoryAttribute att =(System.ComponentModel.CategoryAttribute)oatt; if(att.Category == "Mandatory") { object[] lo = piv.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), true); System.ComponentModel.DescriptionAttribute datt = (System.ComponentModel.DescriptionAttribute)lo[0]; strVerification += "O valor da propriedade " + datt.Description + " é obrigatório"; } } } MessageBox.Show(strVerification); }
Neste exemplo, procedemos da seguinte maneira:
1 - Utilizar a reflexão para ir buscar a "Montagem", que está sendo executada através do método "GetExecutingAssembly ».
2 - Atingir um tipo desta "Montagem" graças ao método "GetType".
3 - Instanciar esta classe de forma genérica usando o método "CreateInstance".
4 - Alcançar uma propriedade desta classe usando a classe "PropertyInfo", que nos dá muitas possibilidades para manipular a nossa propriedade, como atribuir um valor através do método "SetValue "ou ler o valor da propriedade graças ao método "GetValue".
5 - Mas, sobretudo, ler os atributos das propriedades da nossa classe e descobrir quais apresentam uma obrigação de valor não-zero, gerar alertas, e tudo isso, de uma forma genérica.
Esta dica apresenta um primeiro contato com o espaço de nome "System.Reflection". O ponto importante é que agora é possível manipular a "Montagem" (Assembly), os "Tipos" e as "Instâncias", de modo completamente genérico.