IOC在Web API 中是经常使用的,但是在一些WPF项目并不是经常使用或者被人熟知的,我把相关依赖注入的内容又做了一次学习和整理
什么是依赖注入?
依赖注入是一种设计模式和软件设计原则,用于实现 控制反转。它的核心思想是:将对象所依赖的其他对象的创建和管理职责从对象内部转移到外部容器或框架,从而降低代码的耦合度,提高可测试性、可维护性和灵活性。
依赖注入的主要优点
- 降低耦合度(Decoupling):
○ 组件(如 OrderService)只依赖于接口(如 IOrderRepository),而不依赖于具体实现(如 SqlOrderRepository)。具体实现的切换由外部容器控制。 - 提高可测试性(Testability):
○ 可以轻松地为依赖项创建 Mock 或 Stub 对象(实现相同的接口),并在测试时注入到被测试对象中。这使得单元测试独立、快速且可靠(不依赖数据库、网络等外部资源)。 - 提高可维护性和可扩展性:
○ 更容易替换依赖的实现(只需在容器配置中更改绑定关系)。
○ 更容易添加新功能(添加新实现并注册到容器即可)。
○ 代码更清晰,职责更单一。 - 促进代码重用:
○ 解耦后的组件更容易在不同的上下文中复用。 - 管理对象生命周期:
○ DI 容器通常提供对依赖对象生命周期的管理(如单例、每次请求创建新实例、线程内单例等),简化了资源管理。
NET 项目使用依赖注入
● Microsoft.Extensions.DependencyInjection.Abstractions
● Microsoft.Extensions.Dependencyinjection
核心类型
● IServiceCollection 服务注册
● ServiceDescriptor 服务注册时的信息
● IServiceProvider 具体的容器
● IServiceScope 子容器生命周期
生命周期
1.AddSingleton 单例生命周期
● 在整个进程中,多次创建对象都是同一个对象---遵循了单例模式;
● 第一次创建以后,在内存中,保存下来了,下次创建--直接使用内存,而不是再去全新的创建
csharp
ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddSingleton<ITestService, TestService>();
ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();
ITestService testService1 = serviceProvider.GetService<ITestService>();
ITestService testService2 = serviceProvider.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2 {isflg}"); //true
2.AddScoped 作用域生命周期
● 每一个作用域(serviceProvider)内创建的某一个类的对象是同一个实例
● 不同的作用域(serviceProvider)内创建的同一个类的对象是不同的实例
● 这种⽣命周期适⽤于需要在特定作⽤域内共享对象实例的情 况,⽐如Web应⽤程序中的每个HTTP请求
csharp
ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddScoped<ITestService, TestService>();
ServiceProvider serviceProvider1 = serviceDescriptors.BuildServiceProvider();
ITestService testService1 = serviceProvider1.GetService<ITestService>();
ITestService testService2 = serviceProvider1.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2 {isflg}");//true
ServiceProvider serviceProvider2 = serviceDescriptors.BuildServiceProvider();
ITestService testService3 = serviceProvider2.GetService<ITestService>();
ITestService testService4 = serviceProvider2.GetService<ITestService>();
bool isflg1 = object.ReferenceEquals(microphone3, microphone4);
Console.WriteLine($"testService3==testService4 {isflg1}");//true
bool isflg2 = object.ReferenceEquals(testService1, testService3);
Console.WriteLine($"microphone1==microphone3 {isflg2}");//false
3.AddTransient 瞬时生命周期
● 每一次都会创建出一个全新的实例
● 如果需要每次都创建实例---瞬时
csharp
ServiceCollection serviceDescriptors = new ServiceCollection();
serviceDescriptors.AddTransient<ITestService, Microphone>();
ServiceProvider serviceProvider = serviceDescriptors.BuildServiceProvider();
ITestService testService1 = serviceProvider.GetService<ITestService>();
ITestService testService2 = serviceProvider.GetService<ITestService>();
bool isflg = object.ReferenceEquals(testService1, testService2);
Console.WriteLine($"testService1==testService2 {isflg}"); //fals
依赖注入方式
1.构造函数注入
在执行构造函数的时候,能够把构造函数依赖的参数自动构造出来,传递进来;--无限层级
csharp
public class MainViewModel
{
private readonly ITestService _testService;
public MainViewModel(ITestService testService)
{
this._testService = testService;
}
}
2.属性注入
在某个类的内部包含的有属性,在构造出整个类的时候,这个类中的某些属性,能够自动根据属性的类型--自动构造出实例--赋值给属性;
官方不支持需要引入第三方框架
csharp
public class MainViewModel
{
[Inject]
public ITestService TestService { get; set; }
public MainViewModel()
{
}
}
3.方法注入
在某个类的内部,包含的有一些特殊的方法,在构造这个类的实例的时候,能够自动的把方法执行掉,方法需要的参数---自动构建实例,传递进来;
• [FromServices] 需要引用 NuGet 包:Microsoft.AspNetCore.Mvc(仅限 ASP.NET Core 项目)。
csharp
public class MainViewModel
{
public MainViewModel()
{
}
public void Test([FromServices] ITestService testService)
{
testService.GetMessage();
}
}
原生WPF项目使用IOC
csharp
public partial class App : Application
{
public static App CurrentApp { get; private set; } = null!;
public App()
{
CurrentApp = this;
}
public IServiceProvider ServiceProvider { get; set; } = null!;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var serviceCollection = new ServiceCollection();
ConfigureServices(serviceCollection);
this.ServiceProvider = serviceCollection.BuildServiceProvider();
var mainWindow = this.ServiceProvider.GetService<MainWindow>();
mainWindow?.Show();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<MainWindow>();
services.AddSingleton<MainViewModel>();
services.AddTransient<ITestService, TestService>();
}
}
csharp
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = App.CurrentApp.ServiceProvider.GetService(typeof(MainViewModel));
}
}