Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
As árvores de expressão representam o código em uma estrutura de dados semelhante a uma árvore, onde cada nó é uma expressão, por exemplo, uma chamada de método ou uma operação binária como x < y
.
Se você usou o LINQ, tem experiência com uma biblioteca rica onde os Func
tipos fazem parte do conjunto de APIs. (Se você não está familiarizado com o LINQ, provavelmente deseja ler o tutorial do LINQ e o artigo sobre expressões lambda antes deste.) As Árvores de Expressão fornecem uma interação mais rica com os argumentos que são funções.
Você escreve argumentos de função, normalmente usando expressões do Lambda, quando cria consultas LINQ. Em uma consulta LINQ típica, esses argumentos de função são transformados em um delegado que o compilador cria.
Você já escreve código que usa árvores de expressão. As APIs LINQ do Entity Framework aceitam árvores de expressão como argumentos para o padrão de expressão de consulta LINQ. Isso permite que o Entity Framework traduza a consulta que você escreveu em C# em SQL que é executada no mecanismo de banco de dados. Outro exemplo é Moq, que é uma estrutura de simulação popular para .NET.
Quando você quiser ter uma interação mais rica, você precisa usar Árvores de Expressão. As Árvores de Expressão representam o código como uma estrutura que você examina, modifica ou executa. Essas ferramentas oferecem o poder de manipular o código durante o tempo de execução. Você escreve código que examina algoritmos em execução ou injeta novos recursos. Em cenários mais avançados, você modifica algoritmos em execução e até mesmo traduz expressões C# em outro formulário para execução em outro ambiente.
Você compila e executa o código representado por árvores de expressão. A construção e execução de árvores de expressão permite a modificação dinâmica do código executável, a execução de consultas LINQ em vários bancos de dados e a criação de consultas dinâmicas. Para obter mais informações sobre árvores de expressão no LINQ, consulte Como usar árvores de expressão para criar consultas dinâmicas.
As árvores de expressão também são usadas no dynamic language runtime (DLR) para fornecer interoperabilidade entre linguagens dinâmicas e .NET e para permitir que os escritores do compilador emitam árvores de expressão em vez da linguagem intermediária da Microsoft (CIL). Para obter mais informações sobre o DLR, consulte Visão geral do Dynamic Language Runtime.
Você pode fazer com que o compilador C# ou Visual Basic crie uma árvore de expressões para você com base em uma expressão lambda anônima ou você pode criar árvores de expressão manualmente usando o System.Linq.Expressions namespace.
Quando uma expressão lambda é atribuída a uma variável do tipo Expression<TDelegate>, o compilador emite código para criar uma árvore de expressão que representa a expressão lambda.
Os exemplos de código a seguir demonstram como fazer com que o compilador C# crie uma árvore de expressões que representa a expressão num => num < 5
lambda.
Expression<Func<int, bool>> lambda = num => num < 5;
Você cria árvores de expressão em seu código. Você constrói a árvore criando cada nó e anexando os nós em uma estrutura de árvore. Você aprende a criar expressões no artigo sobre como criar árvores de expressão.
As árvores de expressão são imutáveis. Se quiser modificar uma árvore de expressão, você deve construir uma nova árvore de expressão copiando a existente e substituindo nós nela. Você usa um visitante da árvore de expressão para percorrer a árvore de expressão existente. Para obter mais informações, consulte o artigo sobre a tradução de árvores de expressão.
Depois de criar uma árvore de expressão, você executa o código representado pela árvore de expressão.
Limitações
O compilador C# gera árvores de expressão somente a partir das lambdas de expressão (ou lambdas de linha única). Não consegue analisar lambdas de declaração (ou lambdas de múltiplas linhas). Para obter mais informações sobre expressões lambda em C#, consulte Expressões lambda.
Existem alguns elementos mais recentes da linguagem C# que não se traduzem bem em árvores de expressão. As árvores de expressão não podem conter await
expressões ou async
expressões lambda. Muitos dos recursos adicionados no C# 6 e posteriores não aparecem exatamente como escritos em árvores de expressão. Em vez disso, recursos mais recentes são expostos em árvores de expressão na sintaxe equivalente anterior, sempre que possível. Outras construções não estão disponíveis. Isso significa que o código que interpreta árvores de expressão funciona da mesma forma quando novos recursos de linguagem são introduzidos. No entanto, mesmo com essas limitações, as árvores de expressão permitem que você crie algoritmos dinâmicos que dependem da interpretação e modificação de código que é representado como uma estrutura de dados. Ele permite que bibliotecas avançadas, como o Entity Framework, realizem o que fazem.
As árvores de expressão não darão suporte a novos tipos de nó de expressão. Seria uma mudança revolucionária para todas as bibliotecas que interpretam árvores de expressão introduzir novos tipos de nós. A lista a seguir inclui a maioria dos elementos da linguagem C# que não podem ser usados:
- Métodos condicionais removidos da saída
-
base
Acesso - Expressões de grupo de métodos, incluindo endereço de (
&
) um grupo de métodos e expressões de método anônimas - Referências a funções locais
- Declarações, incluindo atribuição (
=
) e expressões com corpo de declaração - Métodos parciais com apenas uma declaração definidora
- Operações de ponteiro inseguras
-
dynamic
operações -
Operadores coalescentes com
null
oudefault
lado esquerdo literal, atribuição de coalescência nula e o operador de propagação nula (?.
) - Inicializadores de matriz multidimensional, propriedades indexadas e inicializadores de dicionário
- Expressões de coleção
-
throw
expressões - Acessar
static virtual
ouabstract
membros da interface - Expressões do Lambda que têm atributos
- Cordas interpoladas
- Conversões de cadeia de caracteres UTF-8 ou literais de cadeia UTF-8
- Invocações de método usando argumentos variáveis, argumentos nomeados ou argumentos opcionais
- Expressões que usam System.Index ou System.Range, operador de índice "do fim" (
^
) ou expressões de intervalo (..
) -
async
expressões lambda ouawait
expressões, incluindoawait foreach
eawait using
-
Literais de tupla, conversões de tupla, tupla
==
ou!=
, ouwith
expressões -
Descarta (
_
), desconstruindo a atribuição, o operador de correspondênciais
de padrões ou a expressão de correspondênciaswitch
de padrões - Chamada COM com
ref
omitida nos argumentos -
ref
,in
ouout
parâmetros,ref
valores de retorno,out
argumentos, ou quaisquer valores doref struct
tipo