2009-08-29 5 views
6

Mi piacerebbe essere in grado di decorare qualsiasi metodo con un attributo personalizzato Trace e qualche parte di codice dovrebbe essere iniettata in quel metodo alla compilazione.Come iniettare codice C# in fase di compilazione?

Ad esempio:

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

dovrebbe diventare:

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

In questo caso, il codice iniettato dipende dal nome metodo e metodo parametri, quindi dovrebbe essere possibile dedurre queste informazioni.

Qualcuno sa come realizzare questo?

risposta

13

Per la programmazione orientata agli aspetti in C#, è possibile utilizzare PostSharp.

(The homepage mostra anche un esempio di Trace, proprio come stai chiedendo!)

+0

Non ho mai studiato le prestazioni del codice PostSharpened, ma sarei sorpreso se lo spessore PostSharp facesse una differenza significativa. – RichieHindle

+0

Non riesco a fare ciò che voglio fare con PostSharp Loas (plugin AOP per PostSharp), ma posso farlo scrivendo un plugin AOP personalizzato per PostSharp. Sebbene PostSharp Loas possa avere influito sulle prestazioni in fase di runtime, il mio plug-in personalizzato non funzionerà poiché sarà solo in fase di compilazione. –

2

Questo può essere fatto facilmente con un sistema di programma di trasformazione.

DMS Software Reengineering Toolkit Il DMS Software Reengineering Toolkit è un sistema di trasformazione di programma generico e può essere utilizzato con molte lingue (C++, COBOL, Java, EcmaScript, Fortran, ..) e in particolare con C#.

DMS analizza il codice sorgente, crea Abstract Syntax Trees e consente di applicare pattern source-to-source per trasformare il codice da un programma C# a un altro con qualsiasi proprietà desideri. La regola di trasformazione per realizzare esattamente il compito specificato sarebbe:

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 } " 

le virgolette (") non sono marchi CSharp quote; anzi, sono 'le citazioni di dominio', e indicano che il contenuto all'interno delle virgolette è la sintassi CSharp (perché abbiamo detto: "CSharp dominio"). le notazioni \ Foo sono meta di sintassi.

Questa regola corrisponde al AST che rappresenta il metodo specificato con il [Trace] annotazioni, e riscrive che AST in la traccia tracciata, l'AST risultante viene quindi riportato di nuovo in forma di origine, che è possibile compilare. Probabilmente occorrono altre regole per gestire altre combinazioni di argomenti; agire, probabilmente si generalizza l'elaborazione dell'argomento per produrre (dove possibile) un valore stringa per ogni argomento scalare.

Dovrebbe essere chiaro che si può fare molto di più del semplice logging con questo, e molto più della semplice programmazione orientata all'aspetto, dal momento che è possibile esprimere trasformazioni arbitrarie e non solo azioni pre-dopo.

+0

Mentre suona molto utile, ho intenzione di provare PostSharp in primo luogo dal momento che è gratuito e l'accesso alla fonte. Sarei anche in grado di rinominare gli attributi in qualsiasi momento e non rompere nulla. –

+0

Perché stai apparentemente obiettando a causa della ridenominazione degli attributi? Se vuoi rinominare gli attributi, puoi anche scrivere una trasformazione del programma per farlo. –