一、依赖注入的核心思想
依赖注入(Dependency Injection,DI)是一种设计模式,它的核心思想是“控制反转”(IoC),即将对象的创建和管理从应用程序代码中分离出来,交给外部容器来处理。主要概念包括:
- 依赖:一个对象需要另一个对象来完成其工作,那么前者就依赖于后者。例如,一个orderService类可能依赖于一个ProductRepository类来获取产品信息;
- 注入:将依赖的对象传递给需要它的对象,而不是让需要它的对象自己去创建依赖的对象。注入可以通过构造函数、属性或方法参数来实现;
- 容器:一个管理对象创建和依赖关系的框架或库。容器负责实例化对象,解析依赖关系,并将依赖的对象注入到需要它们的对象中;
在传统的编程方式中,一个对象如果需要使用另一个对象,通常会在自身内部通过new关键字等方式直接创建被依赖的对象,这就导致了对象之间的紧密耦合。
而在IOC模式下,由IOC容器负责创建对象,并在对象需要时将其依赖的对象注入进去。这样,对象只需要关注自身的业务逻辑,而不需要关心依赖对象的创建过程,从而实现了对象之间依赖关系的解耦。
二、依赖注入的类型
1. 构造函数注入:依赖的对象通过类的构造函数传递。
public class MainViewModel {private readonly IDataService _dataService; public MainViewModel(IDataService dataService){_dataService = dataService;} //使用_dataService的方法 }
2. 属性注入:依赖的对象通过类的公共属性传递。
public class MainViewModel {public IDataService DataService{get; set;} }
3. 方法注入:依赖的对象通过类的方法参数传递。
public class MainViewModel {public void SettingsService(IDataService DataService){//使用DataService的方法 } }
三、WPF中实现依赖注入的常用方式
1. 使用Microsoft.Extensions.DependencyInjection
这是.NET Core/5+中官方推荐的DI容器(.NET Core/5+”涵盖 .NET Core 1.0-3.1 和 .NET 5/6/7/8),.NET提供了一个内置的服务容器IServiceProvider。服务通常在应用启动时注册,并追加到IServiceCollection。添加所有服务后,可以使用BuildServiceProvider创建服务容器。框架负责创建依赖关系的实例,并在不再需要时将其释放。
步骤:
① 首先创建一个WPF应用成,然后再Nuget包管理器中安装微软提供的依赖注入库[Microsoft.Extensions.DependencyInjection];
② 创建测试用的接口ITextService和实现类TextService:
namespace DemoIoc {public interface ITextService{public string GetText();}public class TextService : ITextService{public string GetText(){return DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");}} }
③ 在需要调用的地方(如:MainWindow)进行ITextService接口注入:可以看出MainWindow依赖ITextService接口,而不依赖于接口的实现。这样就实现了依赖注入。
public partial class MainWindow : Window {private ITextService textService;public MainWindow(ITextService textService){this.textService = textService;InitializeComponent();}private void Window_Loaded(object sender, RoutedEventArgs e){this.txtCurrentTime.Text = textService.GetText();} }
④ 配置容器:在启动程序App.xaml.cs中,添加当前对象乘以,和服务提供对象,并在实例化服务对象的时候一次性注册,以便在后续需要的时候进行获取。
// 在App.xaml.cs 中配置服务 public partial class App : Application {public IServiceProvider ServiceProvider{ get; private set;} //获取存放应用服务的容器protected override void OnStartup(StartupEventArgs e){
//配置应用的服务 var serviceCollection = new ServiceCollection();ConfigureServices(serviceCollection); ServiceProvider = serviceCollection.BuildServiceProvider();
//从依赖注入容器中获取一个`MainWindow`类型的实例。var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();mainWindow.Show();}private void ConfigureServices(IServiceCollection services){services.AddSingleton<ITextService, TextService>();Services.AddSingleton<MainWindow>();} }
- AddTransient瞬时模式:每次请求,都获取一个新的实例。使同一个请求获取多次也会是不同的实例
- 使用方式:services.AddTransient<IOperation Transient, Operation>();
- AddScoped:每次请求,都获取一个新的实例。同一个请求获取多次会得到相同的实例
- 使用方式:services.AddScoped<IMyDependency, MyDependenсу>();
- AddSingleton单例模式:每次都获取同一个实例
- 使用方式:services.AddSingleton<IOperationSingleton, Operation>();
2. 使用依赖注入容器(如Autofac,Unity,Ninject等)
依赖注入容器是管理和创建对象及其依赖项的框架。它们可以大大简化依赖注入的实现,尤其是在大型应用中:
-
Autofac: 功能强大,性能好,支持模块化
-
Unity: 微软早期的DI容器,现在较少使用
-
Ninject: 语法简洁,适合快速开发
-
DryIoc: 高性能容器
-
Simple Injector: 强调编译时验证
① Autofac:是 .NET 生态系统中非常流行的轻量级依赖注入(DI)框架,它以高性能和灵活性著称
// 创建注册器 var builder = new ContainerBuilder();// 注册组件 builder.RegisterType<MyService>().As<IMyService>();// 构建容器 var container = builder.Build();// 从容器中解析组件 var myService = container.Resolve<IMyService>();// 使用对象 myService.DoSomething();
② Ninject:是一个轻量级、快速的依赖注入框架,以其"超级流畅"的接口和易用性著称。
// 创建内核(容器) IKernel kernel = new StandardKernel();// 基本绑定 kernel.Bind<IService>().To<ServiceImpl>();// 解析服务 var service = kernel.Get<IService>();// 构造函数注入示例 public class Consumer {private readonly IService _service;public Consumer(IService service) // 自动注入 {_service = service;} }
③ DryIoc: 是另一个高性能的 .NET 依赖注入容器,以其出色的执行速度和简洁的 API 设计受到开发者青睐
// 创建容器 var container = new Container();// 注册服务 container.Register<IMessageService, EmailService>();// 解析服务 var messageService = container.Resolve<IMessageService>();// 使用服务 messageService.SendMessage("Hello, DryIoc!");
④ Unity: 是微软模式与实践团队开发的依赖注入容器,曾是微软官方推荐的DI解决方案。
// 创建容器 IUnityContainer container = new UnityContainer();// 注册类型映射 container.RegisterType<IService, ServiceImpl>();// 解析实例 IService service = container.Resolve<IService>();// 构造函数注入示例 public class Consumer {private readonly IService _service;public Consumer(IService service) // 自动注入 {_service = service;} }