2010-03-02 12 views
41

¿Cuáles son algunos pros/contras para usar la biblioteca Reflection.Emit versus CodeDOM para generar código dinámicamente en tiempo de ejecución?Reflection.Emit vs CodeDOM

Estoy tratando de generar algunas clases dinámicas (relativamente complicadas) en un sistema basado en metadatos disponibles en tiempo de ejecución en formato XML. Generaré clases que amplíen las clases existentes en el ensamblado de la aplicación, implementando interfaces adicionales, agregando métodos y reemplazando a los miembros virtuales y abstractos.

Quiero asegurarme de seleccionar la técnica adecuada antes de profundizar en la implementación. Cualquier información sobre cómo difieren estas diferentes técnicas de generación de código sería útil. Además, cualquier información sobre librerías de código abierto que simplifiquen o simplifiquen el trabajo debilitará cualquiera de las API sería útil también.

+1

Al leer esto, NHibernate fue lo primero que me vino a la cabeza. ¿Valdría la pena mirar cómo lo hacen? – quip

+1

De hecho estoy mirando eso. Usan Reflection.Emit, pero no está claro por qué lo eligieron contra CodeDOM. – LBushkin

Respuesta

50

creo que los puntos clave sobre CodeDOM y Reflection.Emit son los siguientes:

  • CodeDom genera código C# fuente y se utiliza por lo general cuando la generación de código para ser incluido como parte de una solución y compilado en el IDE (por ejemplo, LINQ to SQL classes, WSDL, XSD funcionan todos de esta manera). En este escenario, también puede usar clases parciales para personalizar el código generado. Es menos eficiente, porque genera fuente de C# y luego ejecuta el compilador para analizarlo (¡de nuevo!) Y compilarlo. Puede generar código utilizando construcciones de alto nivel (similares a las expresiones C# &) como bucles.

  • Reflection.Emit genera una IL por lo que produce directamente un conjunto que también se puede almacenar solo en la memoria. Como resultado, es mucho más eficiente. Debe generar código IL de bajo nivel (los valores se almacenan en la pila, el bucle debe implementarse mediante saltos), por lo que generar una lógica más complicada es un poco difícil.

En general, creo que Reflection.Emit se considera generalmente como la forma preferida para generar código en tiempo de ejecución, mientras que CodeDOM se prefiere cuando la generación de código antes de tiempo de compilación. En su escenario, ambos probablemente funcionarían bien (aunque CodeDOM puede necesitar mayores privilegios, porque realmente necesita invocar el compilador C#, que es parte de cualquier instalación .NET).

Otra opción sería usar el Expression class. En .NET 4.0 le permite generar código equivalente a declaraciones y expresiones C#. Sin embargo, no te permite generar clases. Por lo tanto, puede combinar esto con Reflection.Emit (para generar clases que deleguen implementación al código generado usando Expression). Para algunos escenarios, es posible que tampoco necesite una jerarquía de clases completa, a menudo un diccionario de delegados generados dinámicamente como Dictionary<string, Action> podría ser lo suficientemente bueno (pero, por supuesto, depende de su escenario exacto).

+0

Entiendo que CodeDOM también puede [generar código en la memoria] (http://msdn.microsoft.com/en-us/library/system.codedom.compiler.compilerparameters.generateinmemory.aspx)? –

+0

¿Podría explicar cómo puede usar las clases parciales con CodeDom? Si mi investigación indica algo, es que no puede usar 'partial' en absoluto: ni siquiera es una opción en la enumeración' TypeAttributes'. –

+0

Una respuesta completa. Gracias. – nawfal

14

Código que se dirige a CodeDom tiende a ser más fácil de mantener, ya que está generando código C# y no IL (más personas pueden leer C# que IL). Además, si obtiene el código CodeDom incorrecto, obtendrá un error de compilación; si genera IL no válida, obtendrá una excepción fatal o un bloqueo.

Sin embargo, como CodeDom invoca el compilador csc.exe, es un poco más lento obtener el código listo para su uso. Con Reflection.Emit, puede generar código directamente en la memoria.

CodeDom probablemente esté bien para la mayoría de las cosas; el XmlSerializer y el diseñador de WinForms lo usan.

+0

¿Para qué usa el XmlSerializer CodeDOM? Lo siento, podría buscarlo en Reflector pero estoy siendo flojo ya que mi atención está dividida entre muchos otros temas y dado que me respondieron al respecto, supongo que ya invirtió tiempo, así que simplemente puede escribir la respuesta sin pasar demasiado tiempo en ella. ya sea. –

+0

@ WaterCoolerv2 Si tuviera que adivinar, construyen un ensamblaje para leer/escribir los tipos de objetivos. Una vez me llevaron a un proyecto con una monstruosa capa de acceso a datos basada en la reflexión. Era un perro lento, por lo que los usuarios lo odiaban, pero nadie sabía cómo solucionarlo. Lo hice prácticamente instantáneo con una combinación de almacenamiento en caché y Emit. Además de eliminar la reflexión lenta de la imagen, también puede eliminar la sobrecarga inspeccionando primero los tipos y emitiendo códigos de operación apropiados directamente en un método, en lugar de ramificar o llamar a delegados especializados durante el proceso de serialización. – Daniel

Cuestiones relacionadas