Appearance
.NET DI
1. 多构造函数选取规则
DI 会优先选取可注入参数最多的那个构造函数。
csharp
public class ExampleService
{
public ExampleService()
{
}
public ExampleService(ILogger<ExampleService> logger)
{
// omitted for brevity
}
public ExampleService(FooService fooService, BarService barService)
{
// omitted for brevity
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
基于以上这段代码,假定 ILogger<> 已在容器当中注册,并且可被解析,而 FooService 和 BarService 不可被容器解析,则此时容器会选择第二个构造函数来解析 ExampleService 实例,尽管第三个构造函数拥有更多的参数。
当构造函数的选择摸棱两可的时候,则将抛出异常,比如:
csharp
public class ExampleService
{
public ExampleService()
{
}
public ExampleService(ILogger<ExampleService> logger)
{
// omitted for brevity
}
public ExampleService(IOptions<ExampleOptions> options)
{
// omitted for brevity
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2. 服务的生命周期
Transient(瞬态)
- 被注册为 Transient 的服务,每次在被解析时都会创建一个新的对象。
- 这种生存期适用于注册一些轻量级、无状态的服务。
- 对于处理请求的应用程序而言,Transient 的服务将会在请求结束时被释放。
Scoped(范围)
被注册为 Scoped 的服务,在每个作用域内只会创建一个对象。
对于处理请求的应用程序而言,Scoped 的服务将会在请求结束时被释放。
请不要在单例对象中解析具有范围限定的服务,如 Transient。因为这可能导致在处理后续请求的时候单例对象的状态出现异常。
Singleton(单例)
- 被注册为 Singleton 的服务,在每次解析时都返回同一个实例。
- 单例服务创建的时机如下:
- 首次解析单例服务的时候创建
- 由开发人员直接提供一个已实例化的对象
- 对于处理请求的应用程序而言,Singleton 的服务将会在应用程序关闭时随着 ServiceProvider 一起被释放。
3. 注册服务的方法
| 方法 | 自动对象释放 | 多种实现 | 传递参数 |
|---|---|---|---|
Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()示例: services.AddSingleton<IMyDep, MyDep>(); | 是 | 是 | 否 |
Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION})示例: services.AddSingleton<IMyDep>(sp => new MyDep());services.AddSingleton<IMyDep>(sp => new MyDep(99)); | 是 | 是 | 是 |
Add{LIFETIME}<{IMPLEMENTATION}>()示例: services.AddSingleton<MyDep>(); | 是 | 否 | 否 |
AddSingleton<{SERVICE}>(new {IMPLEMENTATION})示例: services.AddSingleton<IMyDep>(new MyDep());services.AddSingleton<IMyDep>(new MyDep(99)); | 否 | 是 | 是 |
AddSingleton(new {IMPLEMENTATION})示例: services.AddSingleton(new MyDep());services.AddSingleton(new MyDep(99)); | 否 | 否 | 是 |
4. 构造函数注入
构造函数的所有参数要么可以被容器解析要么指定默认值。
可以使用以下方式来解析服务:
- IServiceProvider
- ActivatorUtilities
- 可以用来创建未在容器当中注册的对象
- 虽然允许构造函数重载,但构造函数的所有参数都可以由容器进行注入的重载只能有一个
IServiceProvider和ActivatorUtilities只能解析public的构造函数。
5. 根 ServiceProvider
根 ServiceProvider 的生命周期与应用程序的生命周期相同,在关闭应用时释放。
由根 ServiceProvider 直接创建的服务,只有在根 ServiceProvider 释放才会释放。