如何编织C#代码来拦截对构造函数的调用?也许是自定义预处理器或罗斯林
本文关键字:也许 调用 自定义 罗斯林 处理器 预处理 构造函数 编织 何编织 代码 | 更新日期: 2023-09-27 18:33:24
是否有任何类似于[PostSharp] - [注入 - C#预编译器]的解决方案,让我在编译时修改代码?
下面是一个伪代码。
[InterceptCallToConstructors]
void Method1(){
Person Eric = new Person("Eric Bush");
}
InterceptCallToConstructors(ConstructorMethodArgs args){
if(args.Type == typeof(Person))
if(PersonInstances++ > 10 ) args.ReturnValue = null;
}
在此示例中,我们看到如果创建的 Person 超过 10 个,则 Eric 不应包含新的 Person 类。
经过一番研究,我找到了两种解决方案PostSharp和Infuse。使用Infuse,非常复杂且很难检测有多少Person实例,而PostSharp只需一行代码即可检测。
我尝试使用PostSharp进行AOP,但PostSharp目前不支持拦截调用构造函数方面。
据我所知,Roslyn 不支持在编译时修改代码。
这将是一个"自定义预处理器"答案,它修改源代码以实现OP的效果。
我们的 DMS 软件再造工具包及其 C# 前端可以做到这一点。
DMS 提供源到源转换,转换编码为
if you see *this*, replace it by *that*
这是以以下形式编写的:
rule xxx pattern_parameters
this_pattern
-> that_pattern ;
"->"的发音为"替换为::-}
DMS 在 AST(文本到 AST(上运行,因此包括一个解析步骤(文本到 AST(、一个树转换步骤和一个生成最终答案的漂亮打印步骤(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 的完全访问,因此谓词可以在搜索匹配注释时向上或向下爬升。
如果你在 KRuntime (-> ASP.NET 5( 上运行,你可以通过实现 ICompileModule 程序集中立接口来挂钩到编译中。
我建议在:
- 存储库中的 AOP 示例
- 这篇不错的文章