Yo soy el muñeco en este escenario.
He intentado leer en Google cuáles son, pero no lo entiendo. ¿Alguien puede darme una explicación simple de qué son y por qué son útiles?
editar: estoy hablando de la función LINQ en .Net.
Yo soy el muñeco en este escenario.
He intentado leer en Google cuáles son, pero no lo entiendo. ¿Alguien puede darme una explicación simple de qué son y por qué son útiles?
editar: estoy hablando de la función LINQ en .Net.
Respuestas:
La mejor explicación sobre los árboles de expresión que he leído es este artículo de Charlie Calvert.
Para resumirlo;
Un árbol de expresión representa lo que quiere hacer, no cómo quiere hacerlo.
Esta es la diferencia más importante entre delegados y expresiones. Llamas
function
(aFunc<int, int, int>
) sin saber nunca qué hará con los dos enteros que pasaste. Toma dos y devuelve uno, eso es lo máximo que puede saber su código.Ahora, a diferencia de los delegados, su código puede saber qué debe hacer un árbol de expresión.
Eso significa que no puede simplemente invocar un árbol de expresión como podría invocar a un delegado, sino que puede analizarlo. Entonces, ¿qué puede entender su código al analizar la variable
expression
?// `expression.NodeType` returns NodeType.Lambda. // `expression.Type` returns Func<int, int, int>. // `expression.ReturnType` returns Int32. var body = expression.Body; // `body.NodeType` returns ExpressionType.Add. // `body.Type` returns System.Int32. var parameters = expression.Parameters; // `parameters.Count` returns 2. var firstParam = parameters[0]; // `firstParam.Name` returns "a". // `firstParam.Type` returns System.Int32. var secondParam = parameters[1]. // `secondParam.Name` returns "b". // `secondParam.Type` returns System.Int32.
Aquí vemos que hay una gran cantidad de información que podemos obtener de una expresión.
Pero, ¿por qué necesitaríamos eso?
Una vez más, vemos que los árboles de expresión nos permiten representar (¿expresar?) Lo que queremos hacer. Y usamos traductores que deciden cómo se usan nuestras expresiones.
fuente
Un árbol de expresión es un mecanismo para traducir código ejecutable en datos. Usando un árbol de expresión, puede producir una estructura de datos que represente su programa.
En C #, puede trabajar con el árbol de expresión producido por expresiones lambda usando la
Expression<T>
clase.En un programa tradicional, escribe código como este:
double hypotenuse = Math.Sqrt(a*a + b*b);
Este código hace que el compilador genere una asignación, y eso es todo. En la mayoría de los casos, eso es todo lo que le importa.
Con el código convencional, su aplicación no puede retroactivamente y mirar
hypotenuse
para determinar que fue producida al realizar unaMath.Sqrt()
llamada; esta información simplemente no es parte de lo que se incluye.Ahora, considere una expresión lambda como la siguiente:
Func<int, int, double> hypotenuse = (a, b) => Math.Sqrt(a*a + b*b);
Esto es un poco diferente que antes. Ahora
hypotenuse
es en realidad una referencia a un bloque de código ejecutable . Si llamashypotenuse(3, 4);
obtendrá el valor
5
devuelto.Podemos usar árboles de expresión para explorar el bloque de código ejecutable que se produjo. Prueba esto en su lugar:
Expression<Func<int, int, int>> addTwoNumbersExpression = (x, y) => x + y; BinaryExpression body = (BinaryExpression) addTwoNumbersExpression.Body; Console.WriteLine(body);
Esto produce:
Las técnicas y manipulaciones más avanzadas son posibles con árboles de expresión.
fuente
Los árboles de expresión son una representación en memoria de una expresión, por ejemplo, una expresión aritmética o booleana. Por ejemplo, considere la expresión aritmética
a + b*2
Dado que * tiene una precedencia de operadores mayor que +, el árbol de expresión se construye así:
[+] / \ a [*] / \ b 2
Teniendo este árbol, se puede evaluar para cualquier valor de ay b. Además, puede transformarlo en otros árboles de expresión, por ejemplo, para derivar la expresión.
Cuando implemente un árbol de expresión, sugeriría crear una expresión de clase base . Derivado de eso, la clase BinaryExpression se usaría para todas las expresiones binarias, como + y *. Luego, podría introducir una VariableReferenceExpression para hacer referencia a variables (como ayb) y otra clase ConstantExpression (para el 2 del ejemplo).
En muchos casos, el árbol de expresión se crea como resultado de analizar una entrada (directamente del usuario o de un archivo). Para evaluar el árbol de expresión, sugeriría usar el patrón Visitor .
fuente
Respuesta corta: es bueno poder escribir el mismo tipo de consulta LINQ y apuntar a cualquier fuente de datos. No podría tener una consulta "Language Integrated" sin ella.
Respuesta larga: como probablemente sepa, cuando compila el código fuente, lo está transformando de un idioma a otro. Por lo general, de un lenguaje de alto nivel (C #) a un nivel más bajo en (IL).
Básicamente, hay dos formas de hacer esto:
Esto último es lo que hacen todos los programas que conocemos como "compiladores".
Una vez que tenga un árbol de análisis, puede traducirlo fácilmente a cualquier otro idioma y esto es lo que los árboles de expresión nos permiten hacer. Dado que el código se almacena como datos, puede hacer lo que quiera, pero probablemente solo quiera traducirlo a otro idioma.
Ahora, en LINQ to SQL, los árboles de expresión se convierten en un comando SQL y luego se envían por cable al servidor de la base de datos. Hasta donde yo sé, no hacen nada realmente elegante al traducir el código, pero podrían hacerlo . Por ejemplo, el proveedor de consultas podría crear un código SQL diferente según las condiciones de la red.
fuente
IIUC, un árbol de expresión es similar a un árbol de sintaxis abstracta, pero una expresión generalmente arroja un valor único, mientras que un AST puede representar un programa completo (con clases, paquetes, funciones, declaraciones, etc.)
De todos modos, para una expresión (2 + 3) * 5, el árbol es:
* / \ + 5 / \ 2 3
Evalúe cada nodo de forma recursiva (de abajo hacia arriba) para obtener el valor en el nodo raíz, es decir, el valor de la expresión.
Por supuesto, también puede tener operadores unarios (negación) o trinarios (if-then-else) y funciones (n-ary, es decir, cualquier número de operaciones) si su lenguaje de expresión lo permite.
La evaluación de tipos y el control de tipos se realizan sobre árboles similares.
fuente
Los
árboles de expresión DLR son una adición a C # para admitir Dynamic Language Runtime (DLR). El DLR es también el que se encarga de darnos el método "var" para declarar variables. (
var objA = new Tree();
)Más sobre el DLR .
Esencialmente, Microsoft quería abrir CLR para lenguajes dinámicos, como LISP, SmallTalk, Javascript, etc. Para hacer eso, necesitaban poder analizar y evaluar expresiones sobre la marcha. Eso no era posible antes de que surgiera el DLR.
Volviendo a mi primera oración, los árboles de expresión son una adición a C # que abre la capacidad de usar el DLR. Antes de esto, C # era un lenguaje mucho más estático: todos los tipos de variables debían declararse como un tipo específico y todo el código debía escribirse en tiempo de compilación.
Usarlo con
árboles de expresión de datos abre las puertas de inundación al código dinámico.
Digamos, por ejemplo, que está creando un sitio inmobiliario. Durante la fase de diseño, conoce todos los filtros que puede aplicar. Para implementar este código, tiene dos opciones: puede escribir un bucle que compare cada punto de datos con una serie de comprobaciones If-Then; o puede intentar crear una consulta en un lenguaje dinámico (SQL) y pasarla a un programa que pueda realizar la búsqueda por usted (la base de datos).
Con los árboles de expresión, ahora puede cambiar el código en su programa - sobre la marcha - y realizar la búsqueda. Específicamente, puede hacer esto a través de LINQ.
(Ver más: MSDN: Cómo: usar árboles de expresión para crear consultas dinámicas ).
Más allá de los datos
Los usos principales de los árboles de expresión son la gestión de datos. Sin embargo, también se pueden utilizar para código generado dinámicamente. Entonces, si desea una función que se defina dinámicamente (como Javascript), puede crear un árbol de expresión, compilarlo y evaluar los resultados.
Me gustaría profundizar un poco más, pero este sitio hace un trabajo mucho mejor:
Árboles de expresión como compilador
Los ejemplos enumerados incluyen la creación de operadores genéricos para tipos de variables, expresiones lambda manuales, clonación superficial de alto rendimiento y copia dinámica de propiedades de lectura / escritura de un objeto a otro.
Los
árboles de expresión de resumen son representaciones de código que se compila y evalúa en tiempo de ejecución. Permiten tipos dinámicos, lo que es útil para la manipulación de datos y la programación dinámica.
fuente
var
es un azúcar sintáctico en tiempo de compilación; no tiene nada que ver con árboles de expresión, DLR o el tiempo de ejecución.var i = 0
se compila como si escribieraint i = 0
, por lo que no puede usarlovar
para representar un tipo que no se conoce en el tiempo de compilación. Los árboles de expresión no son "una adición para admitir DLR", se introducen en .NET 3.5 para permitir LINQ. DLR, por otro lado, se introduce en .NET 4.0 para permitir lenguajes dinámicos (como IronRuby) y ladynamic
palabra clave. En realidad, los árboles de expresión son utilizados por DLR para proporcionar interoperabilidad, no al revés.¿El árbol de expresiones al que hace referencia es el árbol de evaluación de expresiones?
Si es así, entonces es un árbol construido por el analizador. El analizador usó Lexer / Tokenizer para identificar los tokens del programa. El analizador construye el árbol binario a partir de los tokens.
Aquí está la explicación detallada
fuente