如何使用CodeDOM / T4 / PostSharp等c#自动创建(例如)单例

本文关键字:创建 例如 单例 CodeDOM 何使用 T4 PostSharp | 更新日期: 2023-09-27 18:04:34

我正在寻找一种自动生成(例如)singleton的方法,如:

[SingletonPatternAttribute]
public class Logger {
    public void Log (string txt) { /* do logging... */ }
}

作为消除样板文件的尝试。

有人知道怎么做吗?我知道有CodeDOM, Reflection.Emit, T4等等。此外,还有(最值得注意的)PostSharp,但我真的很高兴看到一个真正的解决上述挑战。

例如,我可以在构造函数中生成代码,但编译时间显然要好得多。 编辑:

这里的问题不是Singleton,而是C#中的生成/元编程-如何以最好的方式创建代码/消除锅炉板-有什么样的具体例子?

如何使用CodeDOM / T4 / PostSharp等c#自动创建(例如)单例

我为我的日志类做了这件事,使用IOC容器并在映射/绑定对象时添加范围。例如,使用Ninject,绑定将是:

Bind<ILogger>().To<Logger>().InSingletonScope();

然后在我想使用单例记录器的类中,我可以使用属性注入:

[Inject]
public ILogger Logger { get; set; }

一段时间过去了,但我还没有收到满意的回复,所以我将把我过去所做的写下来。我仍然对其他方法很感兴趣,因为我觉得我所取得的成就并不理想,我自己想做得更好。

在过去的几年中,我尝试了四种方法中的三种来生成"丰富"类的代码:

  • 反射。发出
  • T4
  • CodeDom(但我很早就放弃了这个,因为它在我的项目的时候,没有完成!)

加上其他三个:

  • IL重写使用分析器API这里和这里(实际使用)
  • 在这里使用ContextBoundObject进行拦截(仅经过测试)
  • 嵌入c#编译器(Roslyn/MonoCSharp)这里和现在也脚本(仅研究,没有实际使用)

总的来说,我研究了所有这些工具,以AOP的方式获得一些代码的"编织",从类似于OP示例的东西开始:使带有"特殊"属性标记的类和方法,修改它们的行为。在我做第一个项目的时候,c#的AOP解决方案还不够成熟(但这可能已经改变了),所以我不能说任何关于PostSharp的事情,比如。正如我所说,我的目的非常相似:基于类和方法的属性,向类添加一些额外的代码(以及类成员)。我不再使用反射。Emit用于原型,IL重写使用Profiler API用于最后的东西。

第二个项目,我最终使用了T4,略有不同;它已经使用了一个代码生成器(更具体地说,是一个解析器生成器),但是我们需要对生成的源代码进行进一步(自动的!)修改。

反射。发出

我使用了以下方法:一个类(让我们称之为MakeProxy)遍历给定的程序集,搜索属性,然后发出一个新的dll("代理"),它在引子下调用原始程序集,为用户提供所需的接口和行为。

我实际上在一个工具中使用了这个类,一个。net可执行文件,在编译通过后由MS Build运行。

主要缺点是:引用可能难以处理。您需要引用自动生成的dll,因此您必须将代码拆分到不同的项目中,甚至不能在解决方案中引用原始项目……这可能是不可接受的。此外,您也"看到"(在IDE中)原始代码,而不是生成的代码;这可能会使调试变得困难。

<<h2>分析器API/h2>在这种情况下,您要做与Reflection相同的工作。Emit,但不需要预构建任何"代理";代码在生成IL时注入(即一次,这在性能方面非常好)。您只需编写(非托管)剖析器DLL,并在其下启动程序。你的"分析器"将得到哪些函数被执行的通知(或者,更好的是,哪些函数被jit了),你可以采取相应的行动。

主要缺点:你不能修改你的类的"结构"(方法,字段,…)(不容易);使用非托管API生成IL非常困难(您必须处理许多事情,当出现问题时进行调试是一场真正的噩梦!)主要优点:不需要对原始代码进行修改(特别是,不需要对调用方进行修改-这就是最终导致我采用该解决方案的原因,给定了特定项目的需求)。

T4

我在一个不同的项目中使用了T4,但我可以在这里分享我的发现。它很适合转换文本,但不适合转换代码:语法变得"奇怪"(你有代码,代码内部的代码生成代码……)你很容易迷路)。

主要优点:它与IDE和构建系统集成得很好;你得到了智能感知支持;这很容易开始;你可以看到你在调试什么

就我个人而言,我想有(或构建自己)像T4的东西,但它执行c# -> c#代码转换;这样,您就可以利用IDE的优势(包括对"原始"answers"生成"的东西的智能感知)和Reflection.Emit的强大功能。你可能需要构建c#/c#编译器和VS插件来获得所有这些好东西。

最后一点:今天,我会使用比Reflection更"高级"的东西。Emit,像IKVM Emit,或者Sigil