【问题标题】:How to inject C# code at compile-time?如何在编译时注入 C# 代码?
【发布时间】:2010-11-24 01:30:24
【问题描述】:

我希望能够使用自定义Trace 属性来装饰任何方法,并且应该在编译时将一些代码注入该方法。

例如:

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

应该变成:

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

在这种情况下,注入的代码取决于方法名和方法参数,所以应该可以推断出这些信息。

有谁知道如何做到这一点?

【问题讨论】:

    标签: c# .net reflection aop trace


    【解决方案1】:

    要在 C# 中进行面向切面编程,可以使用PostSharp

    The homepage 甚至显示 Trace 示例,就像您要求的一样!)

    【讨论】:

    • 我从未研究过 PostSharpened 代码的性能,但如果 PostSharp shim 产生显着差异,我会感到惊讶。
    • 我不能用 PostSharp Loas(PostSharp 的 AOP 插件)做我想做的事情,但我可以通过为 PostSharp 编写一个自定义 AOP 插件来做到这一点。虽然 PostSharp Loas 可能会影响运行时性能,但我的自定义插件不会,因为它只是编译时的。
    【解决方案2】:

    这可以通过程序转换系统轻松完成。

    DMS Software Reengineering Toolkit 是一个通用的程序转换系统,可用于多种语言(C++、COBOL、Java、EcmaScript、Fortran 等),特别是 C#。

    DMS 解析源代码,构建抽象语法树,并允许您应用源到源模式将您的代码从一个 C# 程序转换为另一个具有任何您希望的属性的 C# 程序。完全完成您指定的任务的转换规则是:

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

    引号 (") 不是 CSharp 引号;而是“域引号”,表示引号内的内容是 CSharp 语法(因为我们说的是“域 CSharp”)。\foo符号是元语法。

    此规则匹配表示您指定的方法的 AST, [Trace] 注释,并将该 AST 重写为跟踪形式。然后将生成的 AST 漂亮地打印回源代码形式,您可以对其进行编译。您可能需要其他规则来处理其他参数组合;事实上,您可能会将参数处理概括为(在可行的情况下)为每个标量参数生成一个字符串值。

    应该清楚,您可以做的不仅仅是使用它进行日志记录,而且不仅仅是面向方面的编程,因为您可以表达任意转换,而不仅仅是前后操作。

    【讨论】:

    • 虽然这听起来很有用,但我将首先尝试 PostSharp,因为它是免费的并且可以访问源代码。我也可以在任何时候重命名属性而不破坏任何东西。
    • 为什么你明显反对属性重命名?如果你想重命名属性,你实际上也可以编写一个程序转换来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-14
    相关资源
    最近更新 更多