基本概念
依赖注入(Dependency Injection,简称DI)是一种设计模式,用于实现控制反转(Inversion of Control,简称IoC)原则。依赖注入的主要目的是将对象的创建和对象之间的依赖关系的管理从对象内部转移到外部容器或框架中,从而提高代码的可维护性、可测试性和灵活性,依赖注入是针对项目级而不是功能级。
- 依赖:一个类在执行其功能时需要的其他类或资源。
- 注入:将依赖传递给类的过程,通常在类的构造函数、属性或方法中完成。
本文使用.net core的原生内置框架,主要是为了先去从源头先去弄清楚什么是依赖注入。
NuGet 包:
首先我们要去下载.NET Core内置的依赖注入框架Microsoft.Extensions.DependencyInjection,可以看到它会依赖Microsoft.Extensions.DependencyInjection.Abstractions,所以我们下载时也会自动帮我们安装Abstractions这个包。下载好后,我们就可以使用它提供的容器(ServiceCollection)进行服务注册了。
image.png
image.png
接口和实现
在依赖注入模式里,接口和实现最好是一一对应的,也就是一个接口对应一个实现,不要试图一对多。
- 定义接口:
public interface IEmailService
{
void SendEmail(string to, string body);
}
- 定义实现:
public class EmailService : IEmailService
{
public EmailService()
{
Debug.WriteLine("Create EmailService");
}
public void SendEmail(string to, string body)
{
Debug.WriteLine($"向{to}发送邮件:{body}");
}
}
进行依赖注入
一般我们在MVVM中的viewmodel中进行依赖注入,不会MVVM模式的请看这里WPF之MVVM
MainShellView
<Grid>
<Button Content="button" Width="100" Height="50" Command="{Binding RelayCommand}"/>
</Grid>
MainShellViewModel
public class MainShellViewModel : ViewModelBase
{
private readonly IEmailService _emailService;
public RelayCommand<string?> RelayCommand { get; set; }
public MainShellViewModel(IEmailService emailService)
{
Debug.WriteLine("Create MainShellViewModel");
_emailService = emailService;
RelayCommand = new RelayCommand<string?>(ApplyParam);
}
private void ApplyParam(string? obj)
{
if (obj != null)
{
MessageBox.Show($"有参数:{obj}");
}
_emailService.SendEmail("JSC", "Hello World");
}
}
服务注册:
- 为什么要服务注册?当我们注册服务之后,容器会根据我们注册的服务自动帮我们管理依赖注入,也就是当后面我们用到MainShellViewModel时,它会根据构造函数,自动帮我们生成需要的EmailService实体,也就是容器会自动解析这些依赖,不需要我们手动创建。
- 而且依赖链的自动传递,一旦根对象被解析,其依赖的服务(如ILogger)的构造函数中声明的依赖也会被自动解析。
public partial class App : Application
{
private IServiceProvider _serviceProvider;
public App()
{
var services = new ServiceCollection();
ConfigureServices(services);
_serviceProvider = services.BuildServiceProvider();
}
// 注册服务
private void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IEmailService, EmailService>();
services.AddSingleton<MainShellViewModel>();
}
private void Application_Startup(object sender, StartupEventArgs e)
{
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var mainShellVM = _serviceProvider.GetRequiredService<MainShellViewModel>();
var mainShellView = new MainShellView { DataContext = mainShellVM };
mainShellView.Show();
}
}
服务生命周期
- Singleton:单例,在整个应用程序生命周期内,只创建一个服务实例。无论从容器中请求多少次,都会返回同一个实例。
- Transient:瞬时,每次从容器中请求服务时,都会创建一个新的实例。
- Scoped:作用域,在每个作用域内,服务实例是唯一的。