Um pouco de Reflection #1

22 minuto(s) de leitura - July 15, 2018

01

Fala pessoal, tudo bem?! 💚

Bom pessoal esse será o primeiro artigo de uma série que pretendo escrever sobre Reflection/Lambda/Expression/Expression Tree & Linq, escrever artigos é um hobby, como também é muito gratificante compartilhar conhecimento e impactar pessoas nesse mundo vasto de TI, meus dias são geralmente muito corrido, então sempre que me sobra um tempinho procuro escrever algo. Antes de mais nada quero dizer que esses artigos iniciais serão básicos e introdutório, ao decorrer das próximas séries iremos crescendo a complexidade e nos aprofundando mais no assunto.

FYI:
Quero falar que para mim Reflection/Lambda/Expression/Expression Tree & Linq são as funcionalidades/implementações mais significativas para o .NET/C# tornando a linguagem muito mais poderosa, de forma que podemos escrever códigos mais limpos e com muito mais qualidade.

Vamos falar aqui um pouquinho sobre Reflection de forma introdutória, e nos próximos artigos iremos apresentar mais sobre.
• Lambda Expression
• Expression
• Expresssion Tree

Antes “de mais nada”, vamos usar a classe Aluno como base para exemplos que serão apresentados aqui, estrutura da classe:

public class Aluno
{
    public Guid Id { get; set; }
    public string Nome { get; set; }
    public int Idade { get; set; }
    private DateTime Data { get; set; }

    public void SetAluno(Guid id, string nome, int idade)
    {
        Id = id;
        Nome = nome;
        Idade = idade;
    }
}

1 – Reflection

Poderiamos falar sobre Reflection por muito tempo aqui, mais isso fica para os próximos artigos, já que estamos apenas iniciando nossa série!
O que é Reflection?
Reflection ou Reflexão e uma implementação dentro do .NET onde consegue obter informações dos metadados em tempo de execução, de forma dinâmica. Como por exemplo ler o tipo de dados de uma propriedade e até invocar métodos.
Considerações finais sobre Reflection.
Não é recomendado usar/invocar um método de classe que por design-design você já tem o método disponível, isso se torna trivial e não faz muito sentido.

2 - typeof

O uso do typeof é um dos mais utilizados quando queremos obter informações de algo em tempo de execução. Exemplo:

// Recuperar o nome
var nome = typeof(Aluno).Name;
// Recuperar o nome completo (Namespace + object)
var nomeCompleto = typeof(Aluno).FullName;
// Namespace
var nameSpace = typeof(Aluno).Namespace;

3 - GetType

O uso do GetType se define da mesma forma que o typeof, exceto que as informações que serão recuperadas são de uma instancia. Exemplo:

// Variável / Instância 
var aluno = new Aluno();
// Recuperar o nome
var nome = aluno.GetType().Name;
// Recuperar o nome completo (Namespace + object)
var nomeCompleto = aluno.GetType().FullName;
// Namespace
var nameSpace = aluno.GetType().Namespace;

4 - Reflection + Linq

Vamos usar o Assembly aqui para fazer uma varredura em tempo de execução e recuperar as classes que contém o nome “Aluno”.
A classe Assembly de forma resumida nos fornece possibilidades de obter basicamente tudo existente em nosso assembly como classes, métodos e propriedades, é ai onde entra o Linq para nos ajudar de forma mais elegante e com mais qualidade. Exemplo:

var types = Assembly
    .GetExecutingAssembly()
    .GetTypes()
    .Where(p => p.Name.Contains("Aluno"));

foreach (var type in types)
{
    Console.WriteLine($"Nome..: {type.Name}");
    Console.WriteLine($"Classe: {type.IsClass}");
}

5 - Recuperar propriedades da classe

Veja como é simples recuperar as propriedades de uma classe usando Reflection, o método GetProperties() nos devolve um array do tipo PropertyInfo[] que contém todas propriedades da classe, que por sua vez contém todas informações da propriedade como nome e tipo.
Exemplo:

var propriedades = typeof(Aluno).GetProperties();
foreach (var propriedade in propriedades)
{
    Console.WriteLine($"Nome...: {propriedade.Name}");
    Console.WriteLine($"Tipo...: {propriedade.PropertyType}"); 
} 

01

6 - Invocando método com Reflection

A classe Type nos formece vários métodos para trabalhar em tempo de execução, um deles é o GetMethod que no retorna um MethodInfo, que por sua vez nos permite invocar um método de uma classe, o método pode ser Estático ou Não! Vamos ver um exemplo de como usufruir dessa funcionalidade. Exemplo:

MethodInfo setMetodo = typeof(Aluno).GetMethod("SetAluno");
var parametros = new object[] { Guid.NewGuid(), "Rafael", 29 };
var obj = new Aluno();
setMetodo.Invoke(obj, parametros); 
// Se o método da classe for estático a chamada o invoke ficaria assim:
// setMetodo.Invoke(null, parametros); 

01

7 – Performance

Vamos testar a performance usando Invoke vs Method da classe. Exemplo:

MethodInfo setMetodo = typeof(Aluno).GetMethod("SetAluno");
var parametros = new object[] { Guid.NewGuid(), "Rafael", 29 };
var obj = new Aluno(); 
var interacoes = 10000;

var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < interacoes; i++)
{
    setMetodo.Invoke(obj, parametros);
}
watch.Stop();
Console.WriteLine($"Invoke.......: {watch.Elapsed}");

var idAluno = Guid.NewGuid();
var nomeAluno = "Rafael";
var idadeAluno = 29;

watch.Restart();
for (int i = 0; i < interacoes; i++)
{
    obj.SetAluno(idAluno, nomeAluno, idadeAluno);
}
watch.Stop();
Console.WriteLine($"Metodo Classe: {watch.Elapsed}");

Resultado: 01

Como falei anteriormente a utilização do “Invoke” não é para qualquer situação, principalmente pelos fanáticos por performance como eu, embora seu valor seja tão precioso dentro de todo ecossistema .NET.

Considerações:
Este artigo foi apenas o primeiro passo para série completa que está por vir, iremos iniciar com o básico e iremos evoluir para o complexo, espero que gostem, deixem sugestões do que gostariam de ver nos próximos, algum exemplo do dia-a-dia de vocês.

8 - Exemplo completo

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace ExemploLinqReflection
{
    public class Aluno
    {   
        public Guid Id { get; set; }
        public string Nome { get; set; }
        public int Idade { get; set; }
        private DateTime Data { get; set; }

        public void SetAluno(Guid id, string nome, int idade)
        {
            Id = id;
            Nome = nome;
            Idade = idade;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ////Recuperar o nome
            //var nome = typeof(Aluno).Name;
            //// Recuperar o nome completo (Namespace + object)
            //var nomeCompleto = typeof(Aluno).FullName;
            //// Namespace
            //var nameSpace = typeof(Aluno).Namespace;

            var aluno = new Aluno();
            // Recuperar o nome
            var nome = aluno.GetType().Name;
            // Recuperar o nome completo (Namespace + object)
            var nomeCompleto = aluno.GetType().FullName;
            // Namespace
            var nameSpace = aluno.GetType().Namespace;

            var types = Assembly
                .GetExecutingAssembly()
                .GetTypes()
                .Where(p => p.Name.Contains("Aluno"));

            foreach (var type in types)
            {
                Console.WriteLine($"Nome..: {type.Name}");
                Console.WriteLine($"Classe: {type.IsClass}");
            }

            // Recuperar propriedades da class
            var propriedades = typeof(Aluno).GetProperties();
            foreach (var propriedade in propriedades)
            {
                Console.WriteLine($"Nome...: {propriedade.Name}");
                Console.WriteLine($"Tipo...: {propriedade.PropertyType}"); 
            } 

            MethodInfo setMetodo = typeof(Aluno).GetMethod("SetAluno");
            var parametros = new object[] { Guid.NewGuid(), "Rafael", 29 };
            var obj = new Aluno();
            setMetodo.Invoke(obj, parametros);

            var interacoes = 10000;

            var watch = new Stopwatch();
            watch.Start();
            for (int i = 0; i < interacoes; i++)
            {
                setMetodo.Invoke(obj, parametros);
            }
            watch.Stop();
            Console.WriteLine($"Invoke.......: {watch.Elapsed}");

            var idAluno = Guid.NewGuid();
            var nomeAluno = "Rafael";
            var idadeAluno = 29;

            watch.Restart();
            for (int i = 0; i < interacoes; i++)
            {
                obj.SetAluno(idAluno, nomeAluno, idadeAluno);
            }
            watch.Stop();
            Console.WriteLine($"Metodo Classe: {watch.Elapsed}");

            Console.ReadKey();
        }
    }
}

Referências

Reflection


Pessoal, fico por aqui #reflection #mvp #mvpbr #mvpbuzz #serieralms

Deixe um comentário