有没有类似于 [PostSharp] - [Infuse - A Precompiler for C#] 的解决方案让我在编译时修改代码?

下面是一个伪代码。

[InterceptCallToConstructors]
void Method1(){
    Person Eric = new Person("Eric Bush");
}


InterceptCallToConstructors(ConstructorMethodArgs args){
    if(args.Type == typeof(Person))
        if(PersonInstances++ > 10 ) args.ReturnValue = null;
}

在这个例子中,我们看到如果创建了 10 个以上的 Person,Eric 不应包含新的 Person 类。

经过一番研究,我找到了两种解决方案 PostSharp 和 Infuse。
使用 Infuse,它非常复杂且难以检测有多少 Person 实例使用 PostSharp 检测它是一行代码。

我曾尝试将 AOP 与 PostSharp 一起使用,但 PostSharp 目前不支持拦截 Call To Constructor Aspect。
据我所知,Roslyn 不支持在编译时修改代码。

最佳答案

这将是一个“自定义预处理器”答案,它修改源代码以实现 OP 的效果。

我们的 DMS Software Reengineering Toolkit 及其 C# Front End 可以做到这一点。

DMS 提供源到源转换,转换编码为

if you see *this*, replace it by *that*

这是写成这样的形式:
rule xxx pattern_parameters
    this_pattern
    ->  that_pattern ;

“->”发音为“替换为::-}

DMS 对 AST 进行操作,因此包括解析步骤(文本到 AST)、树转换步骤和生成最终答案的 pretty-print 步骤(AST 到文本)。

OP 似乎想要修改构造函数调用站点(他无法修改构造函数;没有办法让它返回“null”)。为了完成 OP 的任务,他将向 DMS 提供以下源到源转换规范:
       default domain CSharp~v5;  -- says we are working with C# syntax (and need the C# front end)

       rule intercept_constructor(c: IDENTIFIER, a:arguments): expression
           "  new \c (\a) "
       ->  "  \c.PersonInstances==10?null:(PersonInstances++,new \c (\a)) "
           if c == "Person";  -- one might want to force c to be on some qualified path

该规则的作用是找到任意形式的匹配构造函数调用语法,并将其替换为检查 OP 前提条件的条件表达式,如果 Person 实例过多则返回 null(我们在这里修复了 OP 规范中的错误;他似乎增加了计算是否创建了新的 Person 实例,当然不是他的意图)。我们必须限定 PersonInstance 的位置;它不能只是漂浮在以太中。在这个例子中,我建议它是类的静态成员。

详细信息:每个规则都有一个名称(“intercept_constructor”,从 OP 中窃取)。它指的是具有句法形状“new\c (\a)”的句法类别(“表达式”),强制它仅匹配作为表达式的构造函数调用。规则中的引号是元引号;它们将规则语言的语法与目标语言的语法(在本例中为 C#)区分开来。反斜杠是元转义符;元引号中的\c 与元引号外的 c 在规则中的想法相同,对于\a 也是如此。

在一个非常大的系统中,可能有几个 Person 类。我们想确保我们做对了;人们可能需要通过提供路径来将引用的类限定为特定类。 OP 用注释暗示了这一点。如果要检查包含方法上是否存在注释,则需要自定义特殊谓词来请求。 DMS 提供了对此类谓词进行编码的完整工具,包括对 AST 的完全访问,因此谓词可以向上或向下搜索匹配的注释。

关于c# - 如何编写 C# 代码来拦截对构造函数的调用?也许是自定义预处理器或 Roslyn,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27333277/

10-15 17:49