10

查看一个使用Common.Logging for .NET 的项目,我注意到一些类将记录器实例声明为类静态成员。例如:

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
    }
}    

有理由偏爱一种方法吗?

在哪些情况下推荐每种方法?它与线程安全有关吗?

如果我刚刚声明了一个带有静态“记录器”成员的“记录器”类并且整个项目都使用了它(除了我实际上有一个全局变量的问题),这会不会有问题?

4

1 回答 1

12

大多数记录器都是线程安全的,创建它们的实例几乎没有开销,无论是在时间还是内存方面。所以真正的问题需要是从编程和可维护性的角度来看什么是有意义的。

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

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

public class HelloJob : IJob
{
    private readonly ILog _log;

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

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

更新

随着时间的推移,我的观点更多地转向了使用静态记录器的方向。更具体地说,我真的很喜欢使用Fody Anotar库为我生成静态记录器(和其他有用的代码),所以我必须在源代码中编写记录语句,例如:

LogTo.Info("This is a message");
于 2012-12-04T23:48:13.077 回答