views:

641

answers:

2

I would like to be able to decorate any method with a custom Trace attribute and some piece of code should be injected into that method at compilation.

For example:

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

should become:

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

In this case, the injected code depends on the method name and method parameters, so it should be possible to infer this information.

Does anyone know how to accomplish this?

+11  A: 

To do Aspect Oriented Programming in C#, you can use PostSharp.

(The homepage even shows a Trace example, just like you're asking for!)

RichieHindle
I've never studied the performance of PostSharpened code, but I'd be surprised if the PostSharp shim made a significant difference.
RichieHindle
I can't do what I want to do with PostSharp Loas (AOP plugin for PostSharp), but I can do it by writting a custom AOP plugin for PostSharp. While PostSharp Loas might have affected run-time performance, my custom plugin will not since it will be compile-time only.
Hermann
+2  A: 

This can be easily done with a program transformation system.

The DMS Software Reengineering Toolkit is a general purpose program transformation system, and can be used with many languages (C++, COBOL, Java, EcmaScript, Fortran, ..) as well as specifically with C#.

DMS parses source code, builds Abstract Syntax Trees, and allows you to apply source-to-source patterns to transform your code from one C# program into another with whatever properties you wish. THe transformation rule to accomplish exactly the task you specified would be:

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

The quote marks (") are not CSharp quote marks; rather, they are "domain quotes", and indicate that the content inside the quote marks is CSharp syntax (because we said, "domain CSharp"). The \foo notations are meta syntax.

This rule matches the AST representing the method you specified with the [Trace] annotation, and rewrites that AST into the traced form. The resulting AST is then prettyprinted back into source form, which you can compile. You probably need other rules to handle other combinations of arguments; in fact, you'd probably generalize the argument processing to produce (where practical) a string value for each scalar argument.

It should be clear you can do a lot more than just logging with this, and a lot more than just aspect-oriented programming, since you can express arbitrary transformations and not just before-after actions.

Ira Baxter
While this sounds very useful, I am going to try PostSharp first since it's free and access to the source. I would also be able to rename the attributes at any point and not break anything.
Hermann
Why are you apparantly objecting because of attribute renaming? If you want to rename attributes, you can actually write a program transformation to do that, too.
Ira Baxter