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();
}
}
你有几种方法可以做到这一点。
- 如果您希望
Qux
成为 Foo
的实施细节,那么:
public Foo(IBar bar, ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Foo>();
_qux = new Qux(loggerFactory.CreateLogger<Qux>());
}
- 如果您想更正确地使用 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>();
}
- 您可以摆脱
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));
}
旁注:最后一种方法代表了服务定位器反模式并隐藏了日志记录依赖性。仅当您了解以这种方式做事的利弊时才使用。我个人不推荐这种方法。
我正在编写一个 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();
}
}
你有几种方法可以做到这一点。
- 如果您希望
Qux
成为Foo
的实施细节,那么:
public Foo(IBar bar, ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Foo>();
_qux = new Qux(loggerFactory.CreateLogger<Qux>());
}
- 如果您想更正确地使用 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>();
}
- 您可以摆脱
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));
}
旁注:最后一种方法代表了服务定位器反模式并隐藏了日志记录依赖性。仅当您了解以这种方式做事的利弊时才使用。我个人不推荐这种方法。