我有一个习惯将 logger 传递给构造函数,例如:

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 的单例会有什么缺点,所以人们会知道从哪里获取记录器:
    Infrastructure.Logger.Info("blabla");

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

最佳答案


这是真的。但是,对于遍及您拥有的每种类型的跨领域关注点,您只能做很多事情。您必须在任何地方使用记录器,因此您必须拥有这些类型的属性。
所以让我们看看我们能做些什么。
单例
单例很糟糕 <flame-suit-on>
我建议坚持使用属性注入(inject),就像您在第二个示例中所做的那样。这是最好的保理方法,无需求助于魔法。有一个显式的依赖比通过单例隐藏它更好。
但是,如果单例为您节省了大量时间,包括您将不得不进行的所有重构( Crystal 球时间!),我想您可能能够忍受它们。如果曾经有单例的用途,这可能就是它。请记住,如果您想改变主意,成本会很高。
如果您这样做,请使用 the Registry pattern(请参阅说明)以及注册(可重置)单例工厂而不是单例记录器实例的人查看其他人的答案。
还有其他替代方案也可以在没有太多妥协的情况下同样有效,因此您应该首先检查它们。
Visual Studio 代码片段
您可以使用 Visual Studio code snippets 来加速该重复代码的入口。您将能够输入诸如 logger 选项卡之类的内容,代码将神奇地为您显示。
使用 AOP 进行干燥
您可以通过使用 an Aspect Oriented Programming (AOP) framework like PostSharp 自动生成一些属性注入(inject)代码来消除一些属性注入(inject)代码。
完成后它可能看起来像这样:

[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

关于c# - 将记录器作为单例是一个好习惯吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8472678/

10-14 22:07