我有一个将记录器传递给构造函数的习惯,比如:

public class OrderService : IOrderService {
     public OrderService(ILogger logger) {
     }
}

但这很烦人,所以我已经用了一段时间了:

private ILogger logger = NullLogger.Instance;
public ILogger Logger
{
    get { return logger; }
    set { logger = value; }
}

这也很烦人--它不是干的,我需要在每节课上重复这一点.我可以使用基类,但是话又说回来-我使用的是Form类,所以需要FormBase,等等. 所以我想,让单身人士和ILogger一起曝光会有什么坏处,这样每个人都会知道go 哪里找Logger:

    Infrastructure.Logger.Info("blabla");

更新:正如Merlyn正确地注意到的,我应该提到,在第一个和第二个示例中,我使用的是DI.

推荐答案

这也让人恼火——不是DRY

没错.但对于一个贯穿于你所有类型的跨领域问题,你能做的只有这么多.你必须在所有地方安装use个记录器,所以你必须拥有这些类型的属性.

让我们看看我们能做些什么.

单例

单身汉是可怕的<flame-suit-on>人.

我建议坚持使用属性注入,就像您在第二个示例中所做的那样.这是您在不诉诸魔法的情况下所能做的最好的因式分解.具有显式依赖项比通过单例隐藏它要好.

但是,如果单身能为你节省大量时间,包括你必须做的所有重构(水晶球时间!),我想你也许能和他们住在一起.如果说单身有什么用处的话,这可能就是了.请记住,如果你想改变主意,你的成本将是最高的.

如果您这样做,请使用the Registry pattern(参见说明)判断其他人的答案,并判断那些注册了(可重置的)单例factory而不是单例记录器实例的人的答案.

还有其他替代方案可能也同样有效,但不会有太多妥协,所以你应该先看看它们.

Visual Studio代码片段

你可以用Visual Studio代码片段来加速重复代码的输入.你可以输入logger标签之类的内容,代码就会神奇地出现在你面前.

使用面向方面编程(AOP)来烘干

通过使用an Aspect Oriented Programming (AOP) framework like PostSharp自动生成一些属性注入代码,可以消除一点属性注入代码.

当您完成后,它可能看起来像这样:

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

您还可以使用their method tracing sample code自动跟踪方法入口和出口代码,这样就不需要同时添加一些记录器属性.可以在类级别或命名空间范围内应用该属性:

[Trace]
public class MyClass
{
    // ...
}

// or

#if DEBUG
[assembly: Trace( AttributeTargetTypes = "MyNamespace.*",
    AttributeTargetTypeAttributes = MulticastAttributes.Public,
    AttributeTargetMemberAttributes = MulticastAttributes.Public )]
#endif

.net相关问答推荐

ASP.NET核心最小API必须以正斜杠开头吗?

SLN配置文件:映射问题

信号量的多线程问题

在接口内部声明 IEnumerable 而在具体类中声明 IList

将 Span 传递到函数时出现 F# 错误

如何在 Windows 窗体上显示 ClickOnce 版本号

如何创建 LINQ to SQL 事务?

Int32.ToString() 是特定于文化的吗?

在目录中创建应用程序快捷方式

Select 文件夹对话框 WPF

调用委托与方法的性能

支持 HTTPS 的 Httplistener

我们应该总是在类中包含一个默认构造函数吗?

公钥令牌的作用是什么?

在 C# 中将匿名类型转换为键/值数组?

如何使我的托管 NuGet 包支持 C++/CLI 项目?

使用+运算符的字符串连接

为什么 .NET 中没有 Tree 类?

WPF中的依赖属性和附加属性有什么区别?

MultipleActiveResultSets=True 还是多个连接?