.net 控制反转(IoC)和依赖注入(DI)

发布时间 2023-11-27 16:55:48作者: Simian_2018_12_22

引言

控制反转(IoC)实现方法:

  1. (隐式)依赖注入:需要什么服务(类),直接在类里面写,然后系统在创建类的时候给服务(类)自动赋值。
  2. (显式)服务定位器:需要什么服务(类)在给服务定位器要什么服务(类)

1. 初始化使用

引用包:Microsoft.Extensions.DependencyInjection
首先需要创建一个容器:ServiceCollection
然后在容器中注册服务(类)
然后用ServiceProvider获取注册的对象
实例代码:

public interface ITestService
{
    public string Name { get; set; }
    public void SayHi();
}
public class TestServiceImpl : ITestService
{
    public string Name { get; set; }

    public void SayHi()
    {
        Console.WriteLine($"Hi , I'm {Name}");
    }
}
public class TestServiceImpl2 : ITestService
{
    public string Name { get; set; }

    public void SayHi()
    {
        Console.WriteLine($"你好 我是 {Name}");
    }
}
// 容器对象
ServiceCollection services = new ServiceCollection();
// 注册服务
services.AddTransient<TestServiceImpl>();
// 获取注册服务需要用到的工具
using(ServiceProvider serviceProvider = services.BuildServiceProvider())
{
	// 获取注册的服务
    TestServiceImpl test = serviceProvider.GetService<TestServiceImpl>();
    test.Name = "zz";
    test.SayHi();
}

2. 服务使用范围

服务范围分为三种:

  1. 单例:整个容器使用同一个实例对象
  2. 瞬态:每次获取的都是一个新的实例对象
  3. 范围:在一个范围内获取的是同一个实例对象
ServiceCollection services = new ServiceCollection();
//services.AddSingleton<TestServiceImpl>();// 创建单例
services.AddTransient<TestServiceImpl>();// 创建瞬态
//services.AddScoped<TestServiceImpl>();// 创建范围
using (ServiceProvider sp = services.BuildServiceProvider())
{
    TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
    TestServiceImpl t2 = sp.GetService<TestServiceImpl>();
    TestServiceImpl t3 = null;
	// 创建一个范围
    using (IServiceScope scope = sp.CreateScope())
    {
		// 在范围中使用Provider
        t1 = scope.ServiceProvider.GetService<TestServiceImpl>();
        t1.Name = "aa";
        t3 = scope.ServiceProvider.GetService<TestServiceImpl>();
        t3.Name = "dd";
    }
	// 创建一个新的范围
    using(IServiceScope scope = sp.CreateScope())
    {
        t2 = scope.ServiceProvider.GetService<TestServiceImpl>();
        t2.Name = "bb";
    }
    // 单例情况 t1=t2 && t1==t3
    Console.WriteLine(t1==t2 && t1==t3);
    // 瞬态情况 t1!=t2 && t1 != t3
    Console.WriteLine(t1!=t2 && t1 != t3);
    // 范围情况 t1!=t2 && t1 == t3
    Console.WriteLine(t1!=t2 && t1==t3);
    t1.SayHi();
    t2.SayHi();
    t3.SayHi();
}

注册方法和获取实例的方法

ServiceCollection services = new ServiceCollection();
// 注册类与实现类相同
services.AddTransient<TestServiceImpl>();
// 注册类与实现类不同
//services.AddTransient<ITestService,TestServiceImpl>();
// 注册的不同方式,与上面的注册方式结果一致
services.AddTransient(typeof(ITestService),typeof(TestServiceImpl));


// 相同的注册类有多个不同的实现类 
services.AddTransient(typeof(ITestService), typeof(TestServiceImpl2));

using (ServiceProvider sp = services.BuildServiceProvider())
{


    // 如果要获取的注册类不存在GetService则返回null
    TestServiceImpl2 te2 = sp.GetService<TestServiceImpl2>();
    Console.WriteLine(te2);

    // 如果要获取的注册类不存在GetRequiredService则提示错误
    TestServiceImpl2 te3 = sp.GetRequiredService<TestServiceImpl2>();
    Console.WriteLine(te3);


    // 使用注册类获取想要的类
    TestServiceImpl t1 = sp.GetService<TestServiceImpl>();
    // 使用注册类获取想要的类
    //ITestService t2 = sp.GetService<ITestService>();
    // 不使用泛型获取对象 需要手动转换类型 与上面结果一致
    ITestService t2 = (ITestService)sp.GetService(typeof(ITestService));
    t1.Name = "aa";
    t1.SayHi();
    t2.Name = "bb";
    t2.SayHi();

    // 注册多个不同的实现类,如果使用GetService则获取最后注册的实现类
    ITestService t3 = sp.GetService<ITestService>();
    t3.Name = "cc";
    t3.SayHi();

    // 获取多个不同的实现类用GetServices
    IEnumerable<ITestService> t4 = sp.GetServices<ITestService>(); 
    foreach (ITestService t in t4)
    {
        t.Name = "11";
        t.SayHi();
    }

}