Skip to main content

Part2 依赖注入

概念

  • 实现控制反转的两种方式
    • 服务定位(ServiceLocator)
    • 依赖注入(DependencyInjection)
  • 服务: 对象
  • 服务容器: 负责管理注册的服务
  • 查询服务: 创建对象及关联对象
  • 对象生命周期:
    • 瞬态: Transient
    • 范围: Scoped
    • 单例: Singleton
  • 根据类型来获取和注册服务
    • 可以分别指定服务类型和实现类型
    • 服务类型可以是类/接口

生命周期

  • 使用 serviceProvider.CreateScope() 来创建 Scope
  • 如果一个类实现了 IDisposable 接口, 在离开作用域之后容器会自动调用对象的 Dispose 方法
  • 不要在长生命周期的对象中引用比它短的生命周期的对象(ASP.NET Core 中默认抛异常)
    • 例如: 单例中使用瞬态
  • 生命周期的选择
    • 如果类无状态, 建议为 Singleton
    • 如果类有状态, 且有 Scope 控制, 建议为 Scoped, 通常 Scope 控制下的代码都是运行在同一个线程中的, 没有并发修改的
    • 问题

 

/*
 * DI测试1
 */ 
// services.AddTransient<TestService>();
// services.AddSingleton<TestService>();
services.AddScoped<TestService>();

using var serviceProvider = services.BuildServiceProvider();

var testService = serviceProvider.GetService<TestService>();
var testService2 = serviceProvider.GetService<TestService>();
// 如果是瞬态, 返回False, 如果是单例或范围, 返回True
Console.WriteLine(ReferenceEquals(testService, testService2));

/*
 * DI测试2 Scope
 */
TestService? testService3;
TestService? testService4;
using (var scope = serviceProvider.CreateScope())
{
    testService3 = scope.ServiceProvider.GetService<TestService>();
    testService4 = scope.ServiceProvider.GetService<TestService>();
    // True
    Console.WriteLine(ReferenceEquals(testService3, testService4));
}

using (var scope2 = serviceProvider.CreateScope())
{
    var testService5 = scope2.ServiceProvider.GetService<TestService>();
    // False
    Console.WriteLine(ReferenceEquals(testService3, testService5));
}

 

服务定位器 IServiceProvider

 

services.AddScoped<ITestService, TestService>();
services.AddScoped<ITestService, TestService2>();
using var serviceProvider = services.BuildServiceProvider();

// GetService() 如果没有注入, 则返回null
var testService = serviceProvider.GetService<ITestService>();

// GetRequiredService() 如果没有注入, 会抛异常
var testService2 = serviceProvider.GetRequiredService<ITestService>();

// GetServices() 获取多个实现服务
var testServices = serviceProvider.GetServices<ITestService>();
foreach (var item in testServices)
{
    Console.WriteLine(item.GetType().Name);
}