5

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

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

作为消除样板的尝试。

有人知道如何实现吗?我知道有CodeDOM, Reflection.Emit,T4等等。另外 - 有(最值得注意的是)PostSharp,但我很高兴看到上述挑战的真正解决方案。

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

编辑:

这里的问题不是Singleton,而是生成/元编程C#- 如何以最佳方式创建代码/消除样板 - 有哪些具体示例?

4

2 回答 2

2

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

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

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

[Inject]
public ILogger Logger { get; set; }
于 2013-03-18T14:17:58.073 回答
1

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

在过去的几年里,我尝试了四种列出的“丰富”类代码生成方法中的三种:

  • 反射.发射
  • T4
  • CodeDom(但我很早就放弃了这个,因为它是在我的项目时,不完整!)

加上其他三个:

  • IL重写使用Profiler API Herehere(实际使用)
  • 在这里使用 ContextBoundObject 进行拦截(仅测试过)
  • 嵌入 C# 编译器 (Roslyn/MonoCSharp)在这里和现在还有脚本(仅研究,未实际使用)

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

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

反射.发射

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

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

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

探查器 API

在这种情况下,您执行与 Reflection.Emit 相同的工作,但您不需要预先构建任何“代理”;代码在 IL 生成时注入(即一次,这在性能方面非常好)。您只需编写(非托管)探查器 DLL,并在其下启动程序。您的“分析器”将收到有关执行哪些功能(或者更好的是,哪些功能是 JITed)的通知,您可以采取相应的行动。

主要缺点:您不能修改类的“结构”(方法、字段、...)(不容易);使用非托管 API 生成 IL 是相当困难的(你必须处理很多事情,当出现问题时调试是一场真正的噩梦!)主要优点:不需要修改原始代码(尤其是不需要修改调用方 - 考虑到该特定项目的要求,这就是最终导致我走向这个解决方案的原因)。

T4

我将 T4 用于另一个项目,但我可以在这里分享我的发现。它适用于转换文本,但不适用于转换代码:语法变得“奇怪”(您有代码,并且代码中的代码可以生成代码......您很容易迷失方向)。

主要优点:与 IDE 和构建系统很好地集成;你得到智能感知支持;很容易上手;你实际上看到你在调试什么

就个人而言,我希望拥有(或自己构建)像 T4 这样的东西,但它执行 C# -> C# 代码转换;这样,您就可以拥有 IDE 的优势(包括对“原始”和“生产”事物的智能感知)和 Reflection.Emit 的强大功能。您可能需要同时构建 C#/C# 编译器和 VS 插件才能获得所有这些好东西。

最后一点:今天,我会使用比 Reflection.Emit 更“高级”的东西,比如 IKVM emit 或Sigil

于 2013-03-19T12:50:33.513 回答