在C#中,我的Common.Logging记录器应该是实例成员还是静态?

时间:2012-12-04 23:39:18

标签: c# logging common.logging

查看使用a project for .NET的Common.Logging,我注意到有些类将logger实例声明为类静态成员。例如:

public class HelloJob : IJob
{
    private static ILog _log = LogManager.GetLogger(typeof(HelloJob));

    public HelloJob()
    {
    }

    public virtual void  Execute(IJobExecutionContext context)
    {
        _log.Info(string.Format("Hello World! - {0}", System.DateTime.Now.ToString("r")));
    }
}

在其他类中,记录器被声明为实例成员:

public class SimpleExample : IExample
{
    public virtual void Run()
    {
        ILog log = LogManager.GetLogger(typeof (SimpleExample));

        log.Info("------- Initializing ----------------------");

        // etc
    }
}    

是否有理由选择一种方法或另一种方法?

建议采用哪种方法?它与线程安全有关吗?

如果我刚刚宣布一个带有静态“记录器”成员的“Logger”类并且使用了整个项目(除了我在实践中会有一个全局变量的问题),这会是一个问题吗?

1 个答案:

答案 0 :(得分:9)

大多数记录器都是线程安全的,并且创建它们的实例在时间和内存方面都有很小的开销。因此,真正的问题需要从编程和可维护性的角度来看是有意义的。

一方面,由于记录器在概念上与相关联,而不是与类的实例相关联,因此很多人更喜欢将其保持静态。这是一个非常有效的论点。例如,如果HelloWorldJob扩展HelloJob,我认为大多数人都希望HelloJob中的代码编写的日志消息与HelloJob类绑定,即使您有一个更具体的子类实例。能够从静态方法访问您的记录器也很好,如果它不在静态字段上,这是不可能的。

另一方面,没有理由让HelloJob负责获取自己的记录器实例。对于使用依赖注入(单元可测试性,附加可配置性和更简单的代码),有很多要说的。因此,我个人建议让您的记录器由DI框架注入,在这种情况下,需要在每个实例字段上引用它。

public class HelloJob : IJob
{
    private readonly ILog _log;

    public HelloJob(ILog log)
    {
        _log = log;
    }
    ...
}

您的DI框架可以根据它在运行时知道的详细信息设置记录器,或者您可以在单元测试中提供假的或模拟的记录器,以确保生成预期的日志消息。请注意,即使您指的是每个实例字段,您仍可以完全自由地使用每个类(甚至是单个)实例 - 这些只是不需要成为此类的一部分的详细信息关注。