Back-End

3 abr, 2019

C# – Apresentando o tipo Expression

Publicidade

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

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. 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 como definir e invocar uma Expression.

Criando uma Expression

Criaremos 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 criarmos uma Expression. Também teremos 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} ");

Teremos então o código completo do arquivo Program.cs:

Vimos então que quando uma expressão lambda é atribuída 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

Referências