2009-08-29 18 views
6

Me gustaría poder decorar cualquier método con un atributo Trace personalizado y algún fragmento de código debe ser inyectado en ese método en la compilación.Cómo inyectar código C# en tiempo de compilación?

Por ejemplo:

[Trace] 
public void TracedMethod(string param1) 
{ 
    //method body 
} 

debe convertirse en:

public void TracedMethod(string param1) 
{ 
    Log.Trace("TracedMethod", "param1", param1); 
    //method body 
} 

En este caso, el código inyectado depende de los parámetros nombre del método y del método, lo que debe ser posible deducir esta información.

¿Alguien sabe cómo lograr esto?

Respuesta

13

Para hacer la Programación Orientada a Aspectos en C#, puede usar PostSharp.

(The homepage incluso muestra un ejemplo Trace, al igual que lo está pidiendo!)

+0

Nunca he estudiado el rendimiento del código PostSharpened, pero me sorprendería si la corrección PostSharp hiciera una diferencia significativa. – RichieHindle

+0

No puedo hacer lo que quiero hacer con PostSharp Loas (complemento AOP para PostSharp), pero puedo hacerlo escribiendo un plugin AOP personalizado para PostSharp. Si bien PostSharp Loas podría haber afectado el rendimiento en tiempo de ejecución, mi complemento personalizado no lo hará, ya que solo será de tiempo de compilación. –

2

Esto puede hacerse fácilmente con un sistema de transformación de programas.

DMS Software Reengineering Toolkit es un sistema de transformación de programa de propósito general, y se puede usar con muchos lenguajes (C++, COBOL, Java, EcmaScript, Fortran, ..) así como específicamente con C#.

DMS analiza el código fuente, crea árboles de sintaxis abstracta y le permite aplicar patrones de fuente a fuente para transformar su código de un programa C# a otro con las propiedades que desee. La regla de transformación para llevar a cabo exactamente la tarea que ha especificado sería:

domain CSharp. 

insert_trace():method->method 
    "[Trace] 
    \visibility \returntype \methodname(string \parametername) 
    { \body } " 
     -> 
    "\visibility \returntype \methodname(string \parametername) 
    { Log.Trace(\CSharpString\(\methodname\), 
       \CSharpString\(\parametername\), 
       \parametername); 
     \body } " 

Las comillas (") no son comillas CSharp, sino que son 'citas de dominio', e indican que el contenido dentro de las comillas es la sintaxis CSharp (ya dijimos, "dominio CSharp"). las notaciones \ foo son sintaxis meta.

Esta regla coincide con la AST que representa el método que ha especificado con la [traza] anotación, y reescribe que AST en la forma rastreada. Luego, la AST resultante se vuelve a imprimir en forma de fuente, que puede compilar. Probablemente necesite otras reglas para manejar otras combinaciones de argumentos; actuar, probablemente generalizaría el procesamiento del argumento para producir (cuando sea práctico) un valor de cadena para cada argumento escalar.

Debe quedar claro que puede hacer mucho más que simplemente iniciar sesión con esto, y mucho más que solo la programación orientada a aspectos, ya que puede expresar transformaciones arbitrarias y no solo acciones previas y posteriores.

+0

Si bien esto parece muy útil, primero probaré PostSharp ya que es gratis y tengo acceso a la fuente. También podría cambiar el nombre de los atributos en cualquier punto y no romper nada. –

+0

¿Por qué te opones aparentemente por el cambio de nombre de atributo? Si desea cambiar el nombre de los atributos, también puede escribir una transformación de programa para hacerlo también. –

Cuestiones relacionadas