WPF 依赖注入
一、依赖注入的核心思想
依赖注入(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; } }
以Autofac进行举例:
① 基本项目结构:
MyWpfApp/ ├── Views/ │ └── MainWindow.xaml ├── ViewModels/ │ └── MainViewModel.cs ├── Services/ │ ├── IDataService.cs │ └── DataService.cs └── App.xaml.cs
② 安装Autofac包:通过 NuGet 安装必要的包
Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection
③ 创建服务接口和实现
public interface IDataService { string GetData(); } public class DataService : IDataService { public string GetData() { return "数据来自Autofac注入的服务"; } }
④ 创建ViewModel
public class MainViewModel { private readonly IDataService _dataService; public string DisplayData { get; set; } public MainViewModel(IDataService dataService) { _dataService = dataService; DisplayData = _dataService.GetData(); } }
⑤ 配置Autofac容器
public partial class App : Application { public static IContainer Container { get; private set; } protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); // 创建容器构建器 var builder = new ContainerBuilder(); // 注册服务 builder.RegisterType<DataService>().As<IDataService>(); // 注册ViewModels builder.RegisterType<MainViewModel>(); // 注册Views builder.RegisterType<MainWindow>(); // 构建容器 Container = builder.Build(); // 设置服务定位器(可选) var serviceProvider = new AutofacServiceProvider(Container); // 创建并显示主窗口 var mainWindow = Container.Resolve<MainWindow>(); mainWindow.Show(); } }
⑥ 修改MainWindow以支持依赖注入
public partial class MainWindow : Window { public MainWindow(MainViewModel viewModel) { InitializeComponent(); DataContext = viewModel; } }
<Window x:Class="MyWpfApp.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Autofac Demo" Height="350" Width="525"> <Grid> <TextBlock Text="{Binding DisplayData}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20"/> </Grid> </Window>
Autofac高级用法示例
① 生命周期管理
// 单例模式 builder.RegisterType<SingletonService>().As<ISingletonService>().SingleInstance(); // 每个依赖实例 builder.RegisterType<TransientService>().As<ITransientService>().InstancePerDependency(); // 每个生命周期作用域 builder.RegisterType<ScopedService>().As<IScopedService>().InstancePerLifetimeScope();
② 属性注入
public class SomeViewModel { [Inject] // 需要安装 Autofac.Extras.Attributed 包 public ILogger Logger { get; set; } } // 注册时启用属性注入 builder.RegisterType<SomeViewModel>().PropertiesAutowired();
③ 模块化注册
public class ServicesModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<DataService>().As<IDataService>(); builder.RegisterType<Logger>().As<ILogger>(); } } // 在App.xaml.cs中使用模块 builder.RegisterModule<ServicesModule>();
④ 条件注册
// 仅在Debug模式下注册调试服务 #if DEBUG builder.RegisterType<DebugLogger>().As<ILogger>(); #else builder.RegisterType<ProductionLogger>().As<ILogger>(); #endif
浙公网安备 33010602011771号