C# - Apresentando o tipo Expression


  No artigo de hoje vou mostrar como definir e como invocar uma Expression.

Nós já aprendemos (veja as referências no final do artigo) que uma expressão lambda pode ser atribuída aos delegates do tipo Func ou Action para processar as coleções na memória.

O compilador .NET converte a expressão lambda atribuída ao delegate Func ou Action em código executável em tempo de compilação.

A LINQ introduziu um novo Tipo denominado Expression que representa uma expressão lambda fortemente tipada. Assim, agora uma expressão lambda também pode ser atribuída ao tipo Expression<TDelegate>.

O compilador .NET converte a expressão lambda que é atribuída ao tipo Expression<TDelegate> em uma Expression tree em vez de um código executável.

Essa Expression tree ou árvore de expressão é usada pelos provedores de consulta LINQ remotos como uma estrutura de dados para criar uma consulta de tempo de execução a partir dela (como LINQ-to-SQL, EntityFramework ou qualquer outro provedor de consulta LINQ que implemente a interface IQueryable <T>).

Veja na figura abaixo as diferenças quando a expressão lambda é atribuída ao delegado Func ou Action e quando é atribuída ao tipo Expression no LINQ:

Vamos ver então como definir e invocar uma Expression.

Criando uma Expression

Vamos criar um projeto do tipo Console Application no VS 2017 Community.

No projeto Console crie uma classe chamada Aluno com o código abaixo:

Vamos incluir o namespace System.Linq.Expressions no projeto para podermos criar uma Expression.

Para criar uma Expression temos que usar a classe Expression<TDelegate> e vamos precisar criar um delegate do tipo Func ou Action.

Vamos então definir um delegate Func para usar na Expression :

Func<Aluno, bool> isMaiorDeIdade = a => a.Idade > 21 && a.Idade < 20;

Agora basta criar a Expression:

Expression<Func<Aluno, bool>> isMaiorDeIdade_Ex = a => a.Idade > 21 && a.Idade < 20;

Assim convertemos o delegate Func em uma Expression apenas envolvendo o delegate na Expression.

Abaixo temos o código completo do arquivo Program.cs :

Podemos fazer a mesma coisa usando um delegate Action.

Expression <Action<Aluno>> ImprimirNomeAluno = a => Console.WriteLine(a.Nome);

Lembrando que Action não retorna valor.

Invocando uma Expression

Podemos invocar o delegate envolto por uma Expression da mesma maneira que um delegate normal, mas antes temos que compilar o delegate usando o método Compile() que vai retornar um delegate do tipo Func ou Action que poderá ser invocado.

Assim primeiro vamos compilar o delegate Func:

Func<Aluno, bool> isMaiorDeIdade = isMaiorDeIdade_Ex.Compile();

A seguir vamos invocar a Expression e exibir o resultado:

bool resultado = isMaiorDeIdade(new Aluno() { AlunoId = 1,Nome = "Maria",Idade = 51 });
Console.WriteLine($"O aluno é maior de idade ? {resultado} ");

A seguir temos o código completo do arquivo Program.cs :

Vimos então que quando uma expressão lambda é atribuida a uma variável, campo ou parâmetro cujo tipo é Expression<TDelegate> o compilador emite instruções para construir uma Expression Tree.

Na próxima parte do artigo veremos o que é são as Expression Trees.

Pegue o projeto aqui :  CExpressions.zip

"Combati o bom combate, acabei a carreira, guardei a fé.
Desde agora, a coroa da justiça me está guardada, a qual o Senhor, justo juiz, me dará naquele dia;
e não somente a mim, mas também a todos os que amarem a sua vinda. "
2 Timóteo 4:7,8

Referências:


José Carlos Macoratti