2010-06-08 9 views
6

En .NET 2.0-3.5 frameworks, LCG (también conocido como la clase DynamicMethod) era una forma decente de emitir métodos livianos en tiempo de ejecución cuando no se necesitaba una estructura de clases para admitirlos.¿Está ligera la generación de código liviano (LCG)?

En .NET 4.0, los árboles de expresiones ahora admiten instrucciones y bloques, y como tales parecen proporcionar suficiente funcionalidad para construir casi cualquier funcionalidad que pueda requerir de dicho método, y se pueden construir de una manera mucho más fácil y segura que emitir directamente códigos de operación CIL. (Esta afirmación proviene de la experimentación de hoy de convertir algunos de nuestros códigos LCG más complejos para usar compilación y compilación de árbol de expresiones).

¿Hay alguna razón por la cual uno usaría LCG en cualquier código nuevo? ¿Hay algo que pueda hacer que los árboles de expresión no puedan? ¿O es ahora una pieza de funcionalidad "muerta"?

Respuesta

1

Bueno, esta pregunta es bastante antigua ahora, y estoy esperando que se complete un tf get ... así que lo responderé yo mismo.

Sí, LCG está muerto en la mayoría de los casos.

Solíamos hacer un poco de uso de LCG y ahora todo se ha convertido para usar árboles de expresión. Son mucho más fáciles de construir, el código es significativamente más fácil de mantener y depurar, y los mensajes de error son generalmente más informativos que "La operación podría desestabilizar el tiempo de ejecución" cuando se producen errores durante el desarrollo.

Pero, quizás lo más importante, los árboles de expresión son compostables de una manera que Reflection.Emit no lo es. Esto significa que la arquitectura de los componentes utilizados para la generación de código de tiempo de ejecución puede ser más modular e incluso permitir que los complementos amplíen el marco de generación de código.

Lo único que he encontrado que es compatible con Reflection.Emit que no se admite directamente en los árboles de expresiones está configurando los campos .initonly. Sin embargo, esto se puede lograr mediante el uso de una pequeña clase de ayuda y lo alega, en el árbol de expresión, por ejemplo, el que usé es el siguiente:

internal static class FieldHelper 
{ 
    public static TTarget AssignInitOnlyField<TTarget, TField>(
     TTarget target, string fieldName, TField value) 
    { 
     var field = target.GetType().GetField(
      fieldName, 
      BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic); 
     var boxed = (object)target; // required for value type support 
     field.SetValue(boxed, value); 
     return (TTarget)boxed; 
    } 
} 

Vale la pena mencionar el lado negativo de la utilización de árboles de expresión en vez que LCG es que la construcción y compilación de los árboles de expresión es definitivamente más lenta que la emisión directa de los códigos de operación. Suponiendo que está almacenando en caché los métodos compilados, es poco probable que sea un problema importante, pero es la única razón por la que todavía podría obligarlo a usar LCG.

+0

La respuesta es clara, no. LCG es precisamente útil porque permite compilar IL en tiempo de ejecución, lo que lo hace mucho más eficiente. Si no necesita que el código creado sea rápido, no lo necesita. Así que, básicamente, LCG todavía tiene su nicho. – Benja

3

No tiene sentido construir CIL directamente sin pasos intermedios. Pero está perfectamente bien utilizar sus propios lenguajes intermedios que se dirigen a IL al final. Los árboles de expresión, etc., no son suficientes, es solo un idioma, mientras que al implementar las DSL necesitaría muchas semánticas diferentes.

Puede emitir código fácilmente inseguro (con muchos ldftns y similares), puede emitir llamadas finales (no estoy seguro si es posible con expresiones), llamadas no virtuales a métodos virtuales, puede construir de manera eficiente autómatas de estado grande con etiquetas y saltos, etc. Los árboles de expresiones son tan limitantes que simplemente no puedo entender cómo se pueden comparar con un CIL sin procesar.

0

El LCG se refiere a los métodos que se pueden recopilar después de que salgan del alcance. Las expresiones LINQ usan LCG o emiten reflexión normal ... Así que LCG definitivamente no está muerto. Además, las expresiones LINQ no admiten todo, como los parámetros ref, ldtoken, métodos de instancia, propiedades, etc.

0

Los árboles de expresiones son sin duda un camino a seguir para aprovechar al máximo el código generado en tiempo de ejecución.Sin embargo, debe comprender claramente que es limitado y no le proporciona acceso a todo el poder del lenguaje MSIL. Entonces LGC e ILGenerator sin duda se quedarán para las tareas más exigentes.