.net - framework - linq dynamic expression
¿Cuál es un buen caso de uso para.net 4.0 Expression Trees? (9)
Este fue inspirado por mi compañero de trabajo de gurú del lenguaje que parece que no puede encontrar un buen uso para ellos, y después de algunos intentos fallidos por mi cuenta, tengo que estar de acuerdo.
Ahora sé que estos conceptos tienden a fluir mucho más fácilmente una vez que tienes algunas buenas razones prácticas hacia abajo.
En este momento, parece que su único propósito es permitirle escribir un proveedor de Linq.
¿¿Es asi?? ¿Hay otros beneficios a esto?
El árbol de expresiones es tan poderoso porque te permiten tratar el código como datos . Los usuarios están acostumbrados a acumular datos, guardarlos y volver a ellos más tarde.
Los árboles de expresiones le permiten hacer lo mismo con el código. Por ejemplo, puede tomar la entrada de su usuario (casillas de verificación, rangos de números, etc.) y traducirla en un árbol de Expresión. Ese árbol de expresiones puede ejecutarse o almacenarse para su uso posterior. Muy genial.
Piense en los usos prácticos de los informes, como crear y guardar filtros de datos y asignaciones de datos. Otro uso práctico sería admitir flujos de trabajo personalizados en su aplicación basados en reglas definidas por el usuario.
Aquí hay un poco de código de MSDN sobre la serialización de árboles de expresiones ( http://code.msdn.microsoft.com/exprserialization ) que deberían hacer que las ideas fluyan.
He tenido una buena experiencia con ellos transformando mis AST de lenguaje específico de dominio en árboles de expresión. También es bastante fácil con un adaptador de árbol ANTLR para crear un árbol de Expresión directamente desde la gramática.
Los árboles de expresiones .NET 4.0 también son la base para los AST de DLR
Puede usar el árbol de expresiones como un generador de código con un nivel de abstracción más alto que el ensamblado emitido y más rápido que CodeCompiler. Aquí hay una prueba del concepto que solía convencer a nuestro equipo para que los use como un reemplazo de CodeCompiler.
[TestClass]
public class WhenINeedToAccessPropertiesByNameHavingATypeReference
{
public class SomeCategoryData
{
public DateTime CreatedDate { get; set; }
}
[TestMethod]
public void ICanDoThatWithAnExpressionAndItPerformsWell()
{
// INIT
var someCategoryData =
Enumerable.Range(1970, 100).Select(year =>
new SomeCategoryData { CreatedDate = new DateTime(year, 1, 1) }).Cast<object>();
var t = typeof(SomeCategoryData); // or it can be: t = someCategoryData.First().GetType();
var compiled = Stopwatch.StartNew();
// ACT
var filter = AccessPropertyByNameInCompiledMannerSomehow(t, "CreatedDate");
// ASSERT
Trace.WriteLine(string.Format("compiled in: {0}", compiled.Elapsed));
Assert.IsTrue(compiled.ElapsedMilliseconds < 3, "compiles fast enough");
var executed = Stopwatch.StartNew();
// ACT
List<object> result = null;
for (var i = 0; i < 10000; i++)
{
result = someCategoryData.Where(d => filter(d, new DateTime(2000, 1, 1), new DateTime(2009, 1, 1)))
.ToList();
}
executed.Stop();
Trace.WriteLine(string.Format("executed in: {0}", executed.Elapsed));
// ASSERT
Assert.AreEqual(10, result.Count, "insure compiled code actually works");
Assert.IsTrue(executed.ElapsedMilliseconds < 300, "runs fast enough");
}
private static Func<object, DateTime, DateTime, bool>
AccessPropertyByNameInCompiledMannerSomehow(Type t, string fieldToFilterBy)
{
var objectParameter = Expression.Parameter(typeof(object), "p");
var instance = Expression.Convert(objectParameter, t);
var lower = Expression.Parameter(typeof(DateTime), "l");
var upper = Expression.Parameter(typeof(DateTime), "u");
var composite = Expression.Lambda<Func<object, DateTime, DateTime, bool>>(
Expression.And(
Expression.LessThanOrEqual(
lower,
Expression.PropertyOrField(instance, fieldToFilterBy)
),
Expression.GreaterThanOrEqual(
upper,
Expression.PropertyOrField(instance, fieldToFilterBy)
)
), objectParameter, lower, upper
);
return composite.Compile();
}
}
Puedes usar los árboles de expresión para transformar un idioma de dominio en código ejecutable.
Tengo algunos ejemplos here
(perdón por el formato de código roto)
Una solución en busca de un problema, ¿eh?
Los árboles de expresiones le permiten presentar el código como una estructura de datos transformable, por lo que son perfectos para transformar entre los idiomas de los cuales Linq To SQL es el más poderoso actualmente.
Otro uso aparte de los DSL (que es la transformación) es la paralelización (que se divide) y el ejemplo en ese espacio es PLINQ.
vea esta publicación: http://codebetter.com/blogs/gregyoung/archive/2009/10/03/delegate-mapper.aspx Es un gran caso de uso.
La respuesta rápida es "no, no es solo para los proveedores de LINQ ahora". Primero, los árboles de expresiones se extendieron por el tiempo de ejecución de lenguaje dinámico para admitir idiomas dinámicos. Básicamente, si desea trasladar su propio lenguaje dinámico a .NET (como hicieron IronPython e IronRuby), tendrá que usar árboles de expresión. OK, no muchas personas tienen sus propios idiomas. ¿Qué son otros casos de uso? Uno de ellos es generar código dinámico en tiempo de ejecución. Tengo un ejemplo aquí: Generación de métodos dinámicos con árboles de expresión en Visual Studio 2010 . Explica cómo se pueden usar los ET en lugar de generar MSIL para crear métodos dinámicos. De hecho, hay algunos casos de uso para Árboles de Expresión fuera de LINQ incluso en .NET 3.5, pero esas publicaciones aún no se han escrito.