1

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

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

为了使我的库日志框架不可知,我相信最佳实践是将 an 传递ILogger<Foo>给 的构造函数Foo,并将 anILogger<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();
    }
}
4

1 回答 1

3

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

  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. 您可以摆脱 DIQux并获取记录器(如 @canton7 所述):
public Foo(IBar bar, ILogger<Foo> logger)
{
    _logger = logger;
    _qux = new Qux();
}

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

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

于 2021-08-12T09:11:11.437 回答