使用services.AddSingleton<SomeService, SomeServiceImplementation>()
而不是services.AddSingleton<SomeServiceImplementation>()
有什么好处?
例如,我有一个示例接口
interface ISampleInterface
{
void DoSomething();
}
和一个示例类:
class SampleClass : ISampleInterface
{
public void DoSomething()
{
console.write("hi");
}
}
不,我做services.AddSingleton<SampleClass>()
为什么或何时使用services.AddSingleton<ISampleInterface, SampleClass>()
?
谢谢你的帮助!:-(
services.AddSingleton<SampleInterface, SampleClass>()
允许您为同一接口注册不同的实现,而无需修改代码的其余部分。
以最小的工作量更改实施
假设您有一个ILogger
接口和实现,可以将日志记录到浏览器控制台,或者将日志条目发送到不同的服务,例如ConsoleLogger
、MyServiceLogger
或PrometheusLogger
。如果您只注册了实现,例如services.AddSingleton<ConsoleLogger>()
,那么每次更改记录器实现时,您都必须更改所有类。
你必须转到每一页并更改
@inject ConsoleLogger logger;
至
@inject MyServiceLogger logger;
忘记在运行时指定记录器。每次想要使用新的日志记录服务时,都必须部署应用程序。
通过注册接口和特定的实现,您的所有类都可以继续使用ILogger<T>
,并且永远不会知道实现已经更改。
运行时的实施选择
您甚至可以在运行时根据环境变量、配置或您想要的任何其他逻辑来更改实现,例如:
if (app.IsDevelopment)
{
services.AddSingleton<ILogger,ConsoleLogger>();
}
else
{
services.AddSingleton<ILogger,MyServiceLogger>();
}
单元测试
在单元测试中,您可以使用null记录器——事实上,Logging中间件在核心抽象包中有一个NullLogger类正是出于这个原因。
或者,您可以将测试框架的输出方法封装到ILogger
实现中并使用它,而无需修改代码。例如,xUnit为此使用ITestOutputHelper接口。您可以创建一个XUnitlogger
,将调用转发到此接口:
public class XUnitLogger:ILogger
{
private readonly ITestOutputHelper _output;
public XUnitLogger(ITestOutputHelper output)
{
_output=output;
}
...
void Log(...)
{
_output.WriteLine(...);
}
}