如何在使用Attribute装饰的方法中注入/生成管道代码?

Yan*_*ton 10 c# attributes code-generation postsharp syntactic-sugar

我正在阅读有关缓存和记忆的一些文章,以及如何使用委托和泛型轻松实现它.语法非常简单,实现起来非常简单,但我觉得由于重复性,应该可以基于属性生成代码,而不必反复编写相同的管道代码.

假设我们从默认示例开始:

class Foo
{
  public int Fibonacci(int n)
  {
    return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后记住这个:

// 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

我想,一旦找到一个匹配其中一个Memoize扩展方法的标记方法,那么只需要创建一个代码生成器就可以更简单.因此,我可以添加一个属性,而不是编写这个管道代码:

class Foo
{
  [Memoize]
  public int Fibonacci(int n)
  {
    return n > 1 ? Fibonacci(n-1) + Fibonacci(n-2) : n;
  }
}
Run Code Online (Sandbox Code Playgroud)

老实说,我知道这看起来更像是编译器糖应该由预处理器转换而不是实际的代码生成,但我的问题是:

  1. 您认为在ac#源文件中找到具有给定属性的方法,解析出参数类型和返回类型,以及生成与此指纹匹配的委托的最佳方法是什么?
  2. 将此集成到构建过程中的最佳方法是什么,而不会实际覆盖我的代码.是否可以在将源文件传递给编译器之前对源文件进行一些预处理?

感谢您提出的所有想法.

更新:

我已经调查了Shay建议的Postsharp库,它似乎非常适合非时间关键应用程序,如事务管理,跟踪或安全.

然而,当在时间关键的上下文中使用它时,它证明比委托更慢.每次实现的Fibonacci示例的一百万次迭代导致运行时间减慢80倍.(0.012ms postharp vs每次通话0.00015ms代表)

但老实说,在我打算使用它的上下文中,结果是完全可以接受的.谢谢你的回复!

Update2:

显然,Postsharp的作者正在努力研发2.0版,其中包括生成的代码中的性能改进和编译时间.