private class 成员是否应该使用自己的 ILogger 实例?

Should private class member use its own ILogger instance?

我正在编写一个 C# 库,并试图弄清楚如何最好地进行日志记录。我希望我的库可以使用和不使用 DI。

假设我的库有一个名为 Foo 的主要 public class,它通过其构造函数接受 IBar 依赖项,但也有一个硬连接的私有成员输入 Qux(内部 class)。

为了让我的库日志记录框架不可知,我认为最好的做法是将 ILogger<Foo> 传递给 Foo 的构造函数,并将 ILogger<BarImpl> 传递给 IBar.

我的问题是,Qux 应该使用 ILogger<Foo> 记录器,还是应该有自己的记录器 ILogger<Qux>?如果是这样,Foo 将如何创建一个 ILogger<Qux> 传递给 Qux

public interface IBar {}

public class BarImpl : IBar
{
    public BarImpl(ILogger<BarImpl> logger)
    {
    }
}

internal class Qux
{
    public Qux(ILogger<Qux> logger) // should Qux accept ILogger<Qux> or ILogger<Foo>?
    {
    }
}

public class Foo
{
    private Qux _qux;
    
    public Foo(IBar bar, ILogger<Foo> logger)
    {
        // how to create ILogger<Qux> here?
        // _qux = new Qux();
    }
}

你有几种方法可以做到这一点。

  1. 如果您希望 Qux 成为 Foo 的实施细节,那么:
public Foo(IBar bar, ILoggerFactory loggerFactory)
{
    _logger = loggerFactory.CreateLogger<Foo>();
    _qux = new Qux(loggerFactory.CreateLogger<Qux>());
}
  1. 如果您想更正确地使用 DI,并且可以依赖于用户正确使用您的库(如@Llama 所建议):
public Foo(IBar bar, Qux qux, ILogger<Foo> logger)
{
    _logger = logger;
    _qux = qux;
}

// inside your library where you can see the internal Qux
public static IServiceCollection InjectMyLibraryServices(this IServiceCollection services)
{
    // ...
    services.AddScoped<IQux, Qux>();
    services.AddScoped<IFoo, Foo>();
}
  1. 您可以摆脱 Qux 的 DI,只获取记录器(如@canton7 所述):
public Foo(IBar bar, ILogger<Foo> logger)
{
    _logger = logger;
    _qux = new Qux();
}

internal class Qux 
{
    private readonly ILogger _logger = LogManager.GetLogger(typeof(Qux));
}

旁注:最后一种方法代表了服务定位器反模式并隐藏了日志记录依赖性。仅当您了解以这种方式做事的利弊时才使用。我个人不推荐这种方法。