.Net 中使用依赖注入(DI)(一)

.Net 中使用 DI

依赖注入(Dependency Injection,DI)是控制反转(Inversion of Control,IOC)思想的实现方式。

依赖注入简化模块的组装过程,降低模块之间的耦合度

为什么使用DI?

假设有这样的接口和实现类:

public interface ISayHello
{
    public void SayHello();
}

public class Chinese : ISayHello, IDisposable
{
    public void SayHello()
    {
        Console.WriteLine("你好!");
    }

    public void Dispose()
    {
        Console.WriteLine("资源释放了");
    }
}

调用方式:

ISayHello sayHello = new Chinese();
sayHello.SayHello();

基于接口编程自有其好处,但是如上面的方式还是有缺陷的。调用者必须知道是谁实现了ISayHello接口的SayHello方法。这里就需要知道一个接口,一个实现类,加上本身调用的地方,一个简单的调用就有三者耦合。

DI 原理

下面让我们通过 DI 的方式实现,首先是 nuget 安装:

Install-Package Microsoft.Extensions.DependencyInjection -Version 6.0.0

上面包是微软实现的实现了依赖注入的包,看看怎么使用(最麻烦的使用方式):

ServiceCollection serviceContainer = new ServiceCollection();  // 构建一个服务容器
serviceContainer.AddTransient<Chinese>();  // 把 Chinese 作为瞬态服务(对象),添加到服务器容器

// 通过容器构建一个 ServiceProvider(服务提供器),ServiceProvider 可以提供容器中管理的服务(已添加到容器的服务)
using (ServiceProvider serviceProvider = serviceContainer.BuildServiceProvider())  
{
    ISayHello sayHello = serviceProvider.GetService<Chinese>();  // 从 ServiceProvider 中获取需要的服务(对象)
    sayHello.SayHello();
}
  1. 首先创建一个服务(对象)容器
  2. 把需要服务容器管理的服务(对象)添加到服务容器
  3. 通过服务容器构建一个 ServiceProvider(服务提供器),ServiceProvider 可以提供容器管理的服务(已添加到容器的服务)
  4. 通过 ServiceProvider(服务提供器)获取需要的服务(对象)

DI 的生命周期

Transient(瞬态)

使用一次即销毁,下次使用将是一个新的对象

Singleton(单例)

顾名思义,参考单例模式

Scoped(范围)

在一个范围内使用同一个对象

可以通过ServiceProviderCreateScope方法创建新的范围:

ServiceCollection serviceContainer = new ServiceCollection();
serviceContainer.AddScoped<Chinese>();

using (ServiceProvider serviceProvider = serviceContainer.BuildServiceProvider())
{
    ISayHello sayHello1 = serviceProvider.GetService<Chinese>();
    ISayHello sayHello2 = serviceProvider.GetService<Chinese>();
    ISayHello sayHello3 = null;  // 应该在 Scope 范围内声明变量
    ISayHello sayHello4 = null;  // 应该在 Scope 范围内声明变量
    ISayHello sayHello5 = null;  // 应该在 Scope 范围内声明变量
    ISayHello sayHello6 = null;  // 应该在 Scope 范围内声明变量

    using (IServiceScope serviceScope = serviceProvider.CreateScope())
    {
        sayHello3 = serviceScope.ServiceProvider.GetService<Chinese>();
        sayHello4 = serviceScope.ServiceProvider.GetService<Chinese>();
    }

    using (IServiceScope serviceScope = serviceProvider.CreateScope())
    {
        sayHello5 = serviceScope.ServiceProvider.GetService<Chinese>();
        sayHello6 = serviceScope.ServiceProvider.GetService<Chinese>();
    }

    Console.WriteLine(Object.ReferenceEquals(sayHello1, sayHello2));  // True,  都是通过 serviceProvider 创建
    Console.WriteLine(Object.ReferenceEquals(sayHello3, sayHello4));  // True, 都是通过同一个 serviceScope 创建,在单独的一个范围中
    Console.WriteLine(Object.ReferenceEquals(sayHello1, sayHello4));  // False,在单独的一个范围中,所以和 serviceProvider 创建的不一致
    Console.WriteLine(Object.ReferenceEquals(sayHello5, sayHello6));  // True, 同 sayHello3, sayHello4
    Console.WriteLine(Object.ReferenceEquals(sayHello1, sayHello6));  // False,同 sayHello1, sayHello4
    Console.WriteLine(Object.ReferenceEquals(sayHello4, sayHello6));  // False,在两个 serviceScope 中,所以 False
}

在这里插入图片描述

为了确保对象正确的生命周期,应该在 Scope 范围内声明变量

由上图可以知道,如果实现类实现了 IDisposable接口,则在离开作用域之后,容器会自动调用对象的Dispose方法

也印证了需要在范围内声明并使用对象,在外面可能资源被释放了

如何选择生命周期?

如果一个类是无状态的,这时可以选择 Singleton。因为无状态的类无所谓并发问题(不会修改状态)
如果一个类有状态,并且有 Scope 控制,可以注册为 Scoped。因为 Scope 控制的代码都是运行在同一个线程中的,没有并发修改的问题
最后 Transient 在使用时,需要谨慎,因为每次都会创建一个新的对象

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
依赖注入(Dependency Injection,DI)是一种设计模式,其目的是实现对象之间的解耦,提高代码的可测试性和可维护性。在 .NET Core 依赖注入是一个内置的功能,可以通过 ASP.NET Core 的内置容器或第三方容器库来实现。以下是在 .NET Core 使用依赖注入的步骤: 1. 定义接口和实现类 首先,定义需要注入的接口和实现类。例如: ```csharp public interface IMyService { void DoSomething(); } public class MyService : IMyService { public void DoSomething() { // 实现具体逻辑 } } ``` 2. 注册依赖关系 然后,在应用程序的启动代码,注册接口和实现类之间的依赖关系。例如: ```csharp public void ConfigureServices(IServiceCollection services) { services.AddScoped<IMyService, MyService>(); } ``` 上述代码使用 `AddScoped` 方法将 `IMyService` 接口与 `MyService` 实现类进行了注册。`AddScoped` 方法表示每个请求范围内都会创建一个新的实例。 3. 使用依赖注入 现在,可以在需要使用 `IMyService` 的地方进行依赖注入。例如: ```csharp public class MyController : Controller { private readonly IMyService _myService; public MyController(IMyService myService) { _myService = myService; } public IActionResult Index() { _myService.DoSomething(); return View(); } } ``` 上述代码,`MyController` 类在构造函数注入了 `IMyService` 接口,并在 `Index` 方法使用它。 通过以上步骤,就可以在 .NET Core 使用依赖注入了。值得注意的是,ASP.NET Core 的内置容器支持多种生命周期选项,如 `AddSingleton`、`AddTransient` 和 `AddScoped` 等,可以根据实际需求来选择不同的生命周期选项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Qanx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值