Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los árboles de expresión representan código en una estructura de datos similar a un árbol, donde cada nodo es una expresión, por ejemplo, una llamada de método o una operación binaria como x < y
.
Si ha usado LINQ, tiene experiencia con una biblioteca enriquecida donde los Func
tipos forman parte del conjunto de API. (Si no está familiarizado con LINQ, probablemente quiera leer el tutorial de LINQ y el artículo sobre expresiones lambda antes de esta). Los árboles de expresión proporcionan una interacción más completa con los argumentos que son funciones.
Se escriben argumentos de función, normalmente mediante expresiones lambda, al crear consultas LINQ. En una consulta LINQ típica, esos argumentos de función se transforman en un delegado que crea el compilador.
Ya escribe código que usa árboles de expresión. Las API LINQ de Entity Framework aceptan árboles de expresión como argumentos para el patrón de expresión de consulta LINQ. Esto permite a Entity Framework traducir la consulta que escribió en C# en SQL que se ejecuta en el motor de base de datos. Otro ejemplo es Moq, que es un conocido marco de simulación para .NET.
Cuando quiera tener una interacción más enriquecida, debe usar árboles de expresión. Los árboles de expresión representan código como una estructura que se examina, modifica o ejecuta. Estas herramientas proporcionan la capacidad de manipular código durante el tiempo de ejecución. Escribe código que examina los algoritmos en ejecución o inserta nuevas funcionalidades. En escenarios más avanzados, se modifican los algoritmos en ejecución e incluso se traducen expresiones de C# en otro formulario para su ejecución en otro entorno.
Compile y ejecute código representado por árboles de expresión. La creación y ejecución de árboles de expresión permite la modificación dinámica del código ejecutable, la ejecución de consultas LINQ en varias bases de datos y la creación de consultas dinámicas. Para obtener más información sobre los árboles de expresión en LINQ, consulte Uso de árboles de expresión para crear consultas dinámicas.
Los árboles de expresión también se usan en dynamic Language Runtime (DLR) para proporcionar interoperabilidad entre lenguajes dinámicos y .NET y para permitir que los escritores del compilador emitan árboles de expresión en lugar del lenguaje intermedio de Microsoft (CIL). Para obtener más información sobre DLR, consulte Dynamic Language Runtime Overview( Información general sobre Dynamic Language Runtime).
Puede hacer que el compilador de C# o Visual Basic cree un árbol de expresiones según una expresión lambda anónima, o bien puede crear árboles de expresión manualmente mediante el System.Linq.Expressions espacio de nombres .
Cuando se asigna una expresión lambda a una variable de tipo Expression<TDelegate>, el compilador emite código para crear un árbol de expresión que representa la expresión lambda.
En los ejemplos de código siguientes se muestra cómo hacer que el compilador de C# cree un árbol de expresiones que represente la expresión num => num < 5
lambda .
Expression<Func<int, bool>> lambda = num => num < 5;
Los árboles de expresión se crean en el código. Para construir el árbol, cree cada nodo y adjunte los nodos a una estructura de árbol. Aprenderá a crear expresiones en el artículo sobre la creación de árboles de expresión.
Los árboles de expresión son inmutables. Si desea modificar un árbol de expresiones, debe construir un nuevo árbol de expresiones copiando el existente y reemplazando los nodos en él. Se utiliza un visitador de árbol de expresiones para recorrer el árbol de expresiones existente. Para obtener más información, consulte el artículo sobre la traducción de árboles de expresión.
Una vez compilado un árbol de expresiones, ejecute el código representado por el árbol de expresiones.
Limitaciones
El compilador de C# genera árboles de expresión solo a partir de expresiones lambdas (o lambdas de una sola línea). No se pueden analizar lambdas de instrucción (o lambdas de varias líneas). Para obtener más información sobre las expresiones lambda en C#, vea Expresiones lambda.
Hay algunos elementos del lenguaje C# más recientes que no se traducen bien en árboles de expresión. Los árboles de expresión no pueden contener await
expresiones ni async
expresiones lambda. Muchas de las características agregadas en C# 6 y versiones posteriores no aparecen exactamente como se escriben en árboles de expresión. En su lugar, las características más recientes se exponen en árboles de expresión en la sintaxis anterior equivalente, siempre que sea posible. Otros constructos no están disponibles. Significa que el código que interpreta los árboles de expresión funciona igual cuando se introducen nuevas características de lenguaje. Sin embargo, incluso con estas limitaciones, los árboles de expresión permiten crear algoritmos dinámicos que se basan en la interpretación y modificación del código representado como una estructura de datos. Permite que las bibliotecas enriquecidas, como Entity Framework, logren lo que hacen.
Los árboles de expresión no admitirán nuevos tipos de nodo de expresión. Sería un cambio importante para todas las bibliotecas que interpretan los árboles de expresión para introducir nuevos tipos de nodo. En la lista siguiente se incluyen la mayoría de los elementos del lenguaje C# que no se pueden usar:
- Métodos condicionales quitados de la salida
-
base
acceso - Expresiones de grupo de métodos, incluido el grupo del método address-of (
&
) y expresiones de métodos anónimos - Referencias a funciones locales
- Instrucciones, incluidas las expresiones de asignación (
=
) y con cuerpo de instrucción - Métodos parciales con solo una declaración de definición
- Operaciones de puntero no seguras
-
dynamic
Operaciones -
Operadores de fusión con un literal
null
odefault
en la parte izquierdo, asignación de fusión nula y el operador de propagación nulo (?.
) - Inicializadores de matriz multidimensional, propiedades indexadas e inicializadores de diccionario
- Expresiones de colección
-
throw
Expresiones - Acceso a miembros de interfaz
static virtual
oabstract
- Expresiones lambda que tienen atributos
- Cadenas interpoladas
- Conversiones de cadenas UTF-8 o literales de cadena UTF-8
- Invocaciones de método mediante argumentos variables, argumentos con nombre o argumentos opcionales
- Expresiones que usan System.Index o System.Range, índice "desde el final" (operador
^
) o expresiones de rango (..
) -
async
expresiones lambda oawait
expresiones, incluidasawait foreach
yawait using
-
Literales de tupla, conversiones de tupla
==
o!=
o expresioneswith
-
Descartes (
_
), deconstrucción de asignación, operadoris
de coincidencia de patrones o expresiónswitch
de coincidencia de patrones - Llamada COM con
ref
omitido en los argumentos -
ref
,in
oout
parámetros,ref
valores devueltos,out
argumentos o cualquier valor deref struct
tipo