当我正在学习依赖注入时,所以我也分享了我的理解(请在任何你想要的地方纠正我)。下面的示例背后的概念是检查使用依赖注入的优势,因为它有助于在应用程序中实现松散耦合,这将进一步阻止我在具体定义( classes <的情况下在项目中进行大量更改/ em>)将来会发生变化。
IEmailService - 界面:
public interface IEmailService
{
void SendMail();
}
EmailService - 继承上述接口的类
public class EmailService : IEmailService
{
public EmailService(string emailFrom, string emailTo)
{
}
public void SendMail()
{
// Code here
}
}
的HomeController
public class HomeController : Controller
{
private IEmailService _service;
public HomeController(IEmailService service)
{
_service = service;
}
public IActionResult Index()
{
_service.SendMail();
return View();
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
...
services.AddTransient<IEmailService, EmailService>();
...
}
实际假设
我假设之前在 EmailService 类中没有参数化构造函数,但将来我觉得我需要添加一个参数化构造函数,但它不会对这些控制器产生影响(喜欢 HomeController ),它们使用抽象( interfaces )间接访问它们。
不幸的是,当我运行上面的代码时,我得到以下异常,如果我从 EmailService 类中删除参数化构造函数,它似乎就会消失。
InvalidOperationException:尝试激活“DependencyInjectionDemo.Services.EmailService”时无法解析类型“System.String”的服务。
答案 0 :(得分:4)
您可以使用lambda注册EmailService
:
services.AddTransient<IEmailService>(_ => new EmailService("from@", "to@"));
然而, emailFrom
和emailTo
似乎是运行时数据,这意味着Controller可能负责将此信息提供给IEmailService
。由于EmailService
与控制器解耦,这意味着控制器不对其创建负责。
通常,您应该使用运行时数据来防止需要初始化组件(在您的情况下为EmailService
),如here所述,建议是:
在构建期间不要将运行时数据注入应用程序组件;它会导致歧义,使组合根变得更加复杂,并且使得验证DI配置的正确性变得非常困难。我的建议是让运行时数据流过构造对象图的方法调用。
在您的情况下,这基本上意味着将IEmailService
抽象更改为以下内容:
public interface IEmailService
{
void SendMail(string emailFrom, string emailTo);
}