C# IOC 容器实战:KeyedService和生命周期

发布时间:2024年01月13日

前言

我之前写过一篇Ioc容器的使用,用的是微软的IOC容器。这次我们再去深入了解一下IOC 和控制反转

.NET Core 依赖注入 Microsoft.Extensions.DependencyInjection

ASP.NET CORE 内置的IOC解读及使用

ServiceCollection IOC容器 服务的生命周期

Dependency Injection 8.0新功能——KeyedService
作者: 寻己Tenleft
出处:https://www.cnblogs.com/tenleft/p/17719609.html
本站使用「CC BY 4.0」创作共享协议,转载请在文章明显位置注明作者及出处。

详解.NET依赖注入中对象的创建与“销毁”

KeyedService

使用Key值来对类进行区分。

Dependency Injection 8.0新功能——KeyedService

 public class Person
 {


     public List<Phone> Phones { get; set; }

     public Person() {
     
     }

     /// <summary>
     /// 使用拿到对应的
     /// </summary>
     /// <param name="phone1"></param>
     /// <param name="phone2"></param>
     public Person( [FromKeyedServices("A")] Phone phone1, [FromKeyedServices("B")] Phone phone2)
     {
         Phones = new List<Phone>
         {
             phone1,
             phone2
         };
     }
 }


 public class Phone
 {
     public string Name { get; set; }

     public Phone() { }
 }
static void Main(string[] args)
{

    IServiceCollection services = new ServiceCollection()
        .AddSingleton<Person>()
        .AddKeyedScoped<Phone>("A")
        .AddKeyedScoped<Phone>("B");

    var builder = services.BuildServiceProvider();
    
    builder.GetKeyedService<Phone>("A").Name = "大米";
    builder.GetKeyedService<Phone>("B").Name = "小花";

    var person = builder.GetService<Person>();

    Console.WriteLine(JsonConvert.SerializeObject(person));



    Console.WriteLine("运行完成!");
    Console.ReadKey();
}

在这里插入图片描述

也可以这么写

 static void Main(string[] args)
 {

     IServiceCollection services = new ServiceCollection()
         .AddSingleton<NetCore.Models.Person>()
         .AddKeyedScoped<Phone>("A", (sp,key) =>
         {
             return new Phone() {Name = "小花" };
         })
         .AddKeyedScoped<Phone>("B", (sp, key) =>
         {
             return new Phone() { Name = "大米" };
         });

     var builder = services.BuildServiceProvider();
     


     var person = builder.GetService<NetCore.Models.Person>();

     Console.WriteLine(JsonConvert.SerializeObject(person));



     Console.WriteLine("运行完成!");
     Console.ReadKey();
 }

Key缺少

如果Key的构造函数对应不上,就会出现问题

在这里插入图片描述
在这里插入图片描述

Key值覆盖

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

KeyedService.AnyKey

因为之前的KeyService的要求是必须声明,才能注入,如果缺一个就直接不走构造函数了,实在是太严格了。

使用KeyedService.AnyKey就是尽可能的获取对应的Key的服务

        static void Main(string[] args)
        {

            IServiceCollection services = new ServiceCollection()
                .AddSingleton<NetCore.Models.Person>()
                .AddKeyedScoped<Phone>(KeyedService.AnyKey);

            var builder = services.BuildServiceProvider();
            //builder.GetServices<Phone>();
            var res =  builder.GetKeyedService<Phone>("A");
            Console.WriteLine(res.Name);
            var person = builder.GetService<NetCore.Models.Person>();

            Console.WriteLine(JsonConvert.SerializeObject(person));



            Console.WriteLine("运行完成!");
            Console.ReadKey();
        }
public class Phone
{

    public string Name { get; set; }

    public Phone() { }

    /// <summary>
    /// 尝试去拿Key的值
    /// </summary>
    /// <param name="key"></param>
    public Phone([ServiceKey] string key )
    {
        Console.WriteLine($"我拿到Key了{key}");
    }
    
}

在这里插入图片描述

生命周期

详情可以看这篇文章,写的是真的厉害

详解.NET依赖注入中对象的创建与“销毁”

测试代码

  • this.GetHashCode()会返回每个新对象唯一的code,来区分对象
  • 继承IDisposable后,IOC容器会在合适的地方自动调用Dispose方法
public class SingleService : IDisposable
{
    public string Name { get; set; }

    public SingleService([ServiceKey] string key)
    {
        Name = key;
        Console.WriteLine($"我被创造了[{Name}]-{this.GetHashCode()}");
    }


    public void Dispose()
    {
        Console.WriteLine($"我被销毁了[{Name}]-{this.GetHashCode()}");

    }
}

public class ScopedService : IDisposable
{
    public string Name { get; set; }

    public ScopedService()
    {
        Console.WriteLine($"我被创造了[{Name}]-{this.GetHashCode()}");

    }

    public ScopedService([ServiceKey] string key)
    {
        Name = key;
        Console.WriteLine($"我被创造了[{Name}]-{this.GetHashCode()}");
    }


    public void Dispose()
    {
        Console.WriteLine($"我被销毁了[{Name}]-{this.GetHashCode()}");

    }


}

public class TransientService : IDisposable
{
    public string Name { get; set; }

    public TransientService([ServiceKey] string key)
    {
        Name = key;
        Console.WriteLine($"我被创造了[{Name}]-{this.GetHashCode()}");
    }



    public void Dispose()
    {
        Console.WriteLine($"我被销毁了[{Name}]-{this.GetHashCode()}");

    }
}

static void Main(string[] args)
{

    var services = new ServiceCollection()
        .AddKeyedSingleton<SingleService>(KeyedService.AnyKey)
        .AddKeyedScoped<ScopedService>(KeyedService.AnyKey)
        .AddKeyedTransient<TransientService>(KeyedService.AnyKey).BuildServiceProvider();

    Console.WriteLine();

    services.GetKeyedService<SingleService>("A");
    services.GetKeyedService<ScopedService>("B");
    services.GetKeyedService<TransientService>("C");
    Console.WriteLine();
    services.GetKeyedService<SingleService>("A");
    services.GetKeyedService<ScopedService>("B");
    services.GetKeyedService<TransientService>("C");

    //测试Scoped
    using (var scope = services.CreateScope())
    {
        Console.WriteLine("");

        scope.ServiceProvider.GetKeyedService<SingleService>("A");
        scope.ServiceProvider.GetKeyedService<ScopedService>("B");
        scope.ServiceProvider.GetKeyedService<TransientService>("C");
    }

    Console.WriteLine();

    Console.WriteLine("运行完成!");
    Console.ReadKey();
}

在这里插入图片描述

总结

这次算是补上了上次的坑,彻底弄懂了IOC 容器的生命周期。怎么玩我还不了解,懂了至少吹牛逼的时候有谈资。

文章来源:https://blog.csdn.net/qq_44695769/article/details/135571044
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。