I was reading through some articles on Caching and Memoization and how to implement it easily using delegates and generics. The syntax was pretty straightforward, and it is surprisingly easy to implement, but I just feel due to the repetitive nature it should be possible to generate code based on an Attribute, instead of having to write the same plumbing code over and over.
Let's say we start off with the default example:
class Foo
{
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
And then to memoize this:
// Let's say we have a utility class somewhere with the following extension method:
// public static Func<TResult> Memoize<TResult>(this Func<TResult> f)
class Foo
{
public Func<int,int> Fibonacci = fib;
public Foo()
{
Fibonacci = Fibonacci.Memoize();
}
public int fib(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
I thought, wouldn't it be simpler to just make a code generator that spits out this code, once it finds a tagged method that matches one of the Memoize extension methods. So in stead of writing this plumbing code, I could just add an attribute:
class Foo
{
[Memoize]
public int Fibonacci(int n)
{
return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
}
}
Honestly, I know this is looking more like compiler sugar that should be converted by a preprocessor than actual code generation but my question is:
- What do you think is the best way to find the methods in a c# source file that have a given attribute, parsing out the parametertypes and returntype, and generating a delegate that matches this fingerprint
- What would be the best way to integrate this into the build process, without actually overwriting my code. Is it possible to do some preprocessing on the source files before passing it on to the compiler?
Thanks for any and all ideas.
Update:
I have looked into the Postsharp library as Shay had suggested, and it seemed very suited for the job on non time-critical applications like Transaction Management, Tracing or Security.
However when using it in a time-critical context it proved a LOT slower than the delegate. One million iterations of the Fibonacci example with each implementation resulted in a 80x slower runtime. (0.012ms postsharp vs 0.00015ms delegate per call)
But honestly the result is completely acceptable in the context in which I intend to use it. Thanks for the responses!
Update2:
Apparently the author of Postsharp is working hard on a release 2.0 which will include, among other things, performance improvements in produced code, and compile time.