【问题标题】:Adding a implementation rather than its interface in ASP.NET Core DI在 ASP.NET Core DI 中添加实现而不是其接口
【发布时间】:2018-08-16 23:01:03
【问题描述】:
添加一个实现而不是它的接口有什么区别,因为我只有这个接口的一个实现?
// Adds a transient service by type of the implementation:
services.AddTransient(typeof(SomeConcreteService));
或
// Adds a transient service by interface of the concrete implementation type:
services.AddTransient<ISomeService, SomeConcreteService>();
【问题讨论】:
标签:
c#
asp.net-core
dependency-injection
【解决方案1】:
今天你有一个接口的实现。明天你可能不会。其他人将来可能需要使用decorator、composite 或其他设计模式来扩展服务。
从本质上讲,通过使用接口,您的应用程序可以应对各种可能性 - 它甚至可以以您今天无法预见的方式进行扩展,而无需更改 DI 容器注册之外的任何一行代码。
如果使用具体类型,扩展它的能力非常有限。您基本上是在说“这将是永远的方式”,而不允许在不更改代码的情况下扩展它的许多可能性。您正在放弃使用 DI 模式最有用的好处 - 通过将其接口与其实现分离来松散耦合您的代码。
【解决方案2】:
当您添加实现时,您只能将其作为实现注入。
services.AddTransient(typeof(SomeConcreteService));
现在将其作为ISomeService 注入将导致错误。
此时
services.AddTransient<ISomeService, SomeConcreteService>();
将允许您注入接口而不是实现。
最后是关于loosley coupeling。它还使您的软件更难测试。
如果您只注入接口,您可以轻松地测试使用具有给定接口的实现的类 bc 您可以毫无问题地模拟它。如果您不注入真正的实现,则必须将实现的功能标记为虚拟以模拟它们。您还需要模拟您的实现 SomeConcreteService 可能正在使用的类。
【解决方案3】:
services.AddTransient<ISomeService, SomeConcreteService>();
这种方式是首选,因为它可以让您以正确的方式使用依赖注入。
如果您在所有控制器中使用接口,然后决定要更改具体实现,则只需编辑 Startup.cs 中的一行
public HomeController(ISomeService someService)
{
//..
}