• 注入一接口多实例,小心有坑


      asp.net core后期的版本支持在依赖注入时,一个接口,多个子类实现,依次注入,当需要使用实例时,可以用IEnumerable<接口>来获取实例,进行使用,这种使用方式如下:

      接口和子类的定义:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MultiChildDI.Services
    {
        public interface IDemoService
        {
            void F1();
        }
        public class DemoService01 : IDemoService
        {
            public DemoService01()
            {
                Console.WriteLine("---------------DemoService01");
            }
            public void F1()
            {
                Console.WriteLine("---------------DemoService01.F1()");
            }
        }
        public class DemoService02 : IDemoService
        {
            public DemoService02()
            {
                Console.WriteLine("---------------DemoService02");
            }
            public void F1()
            {
                Console.WriteLine("---------------DemoService02.F1()");
            }
        }
        public class DemoService03 : IDemoService
        {
            public DemoService03()
            {
                Console.WriteLine("---------------DemoService03");
            }
            public void F1()
            {
                Console.WriteLine("---------------DemoService03.F1()");
            }
        }
    }

    注入

    public void ConfigureServices(IServiceCollection services)
    {            
         services.AddScoped<IDemoService, DemoService01>();
         services.AddScoped<IDemoService, DemoService02>();
         services.AddScoped<IDemoService, DemoService03>();
    }

    调用

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Logging;
    using MultiChildDI.Services;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace MultiChildDI.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class HomeController : ControllerBase
        {
            private readonly ILogger<HomeController> _logger;
            private readonly IEnumerable<IDemoService> _services;
            public HomeController(ILogger<HomeController> logger, IEnumerable<IDemoService> services)
            {
                _services = services;
                _logger = logger;
            }
            [HttpGet("/first")]
            public string First()
            {   
                _logger.LogInformation("first");
                var demo01 = _services.SingleOrDefault(s=>s.GetType().Name=="DemoService01");
                demo01.F1();         
                return "ok";
            }
            [HttpGet("/seconderror")]
            public string SecondError([FromServices] IServiceProvider provider)
            {
                var demo01 = provider.GetService<DemoService01>();
                demo01.F1();
                return "ok";
            }
            [HttpGet("/second")]
            public string Second([FromServices]IServiceProvider provider)
            {
                _logger.LogInformation("second");
                var demo01 = provider.GetServices<IDemoService>().First();
                demo01.F1();
                return "ok";
            }
        }
    }

      这样使用,当子类比较少时可以,或者当注入的单例模式问题不大,如果子类比较多,并且是非单列模式,就会在每次调用时,把所有的子类都实例化,但一个请求,有可能只调用一个子类里的功能,这样就造成其他子类实例化的大量开销浪费,问题每次调用的这个请求都浪费,特别是要求高性能的应用。运行结果如下。

     

     

     

      为了改进这个问题,可以用一个工厂来处理这个问题,只实例化要使用的子类即可。

      注入

    public void ConfigureServices(IServiceCollection services)
    {  
        services.AddScoped<DemoService01>();
        services.AddScoped<DemoService02>();
        services.AddScoped<DemoService03>();
        services.AddScoped<IDemoServiceFactory, DemoServiceFactory>();
    }

      工厂类

     public interface IDemoServiceFactory
     {
         IDemoService Create(string name);
     }
     public class DemoServiceFactory : IDemoServiceFactory
     {
         private readonly IServiceProvider _provider;
         public DemoServiceFactory(IServiceProvider provider)
         {
             _provider = provider;
         }
    
         public IDemoService Create(string name)
         {
             var type = Assembly.GetAssembly(typeof(DemoServiceFactory)).GetType($"MultiChildDI.Services.DemoService{name}");
             var instance = _provider.GetService(type);
             return instance as IDemoService;
         }
     }

      使用方式

    private readonly ILogger<HomeController> _logger;
    private readonly IDemoServiceFactory _factory;
    
    public HomeController(ILogger<HomeController> logger, IDemoServiceFactory factory)
    {
        _factory = factory;
        _logger = logger;
    }
    [HttpGet]
    public string Get(string name)
    {
        //根据业务分别实例化不同的子类
        var demo = _factory.Create(name);
        demo.F1();
        return "ok";
    }

      调用三个子实例的结果,每次只实例化要使用的子类,节省开销。

     

     

     

      想要更快更方便的了解相关知识,可以关注微信公众号 
     

     

     

  • 相关阅读:
    CD4051
    sbit和sfr的定义
    EEPROM与FLASH的区别
    九LWIP学习笔记之最后的战役
    八LWIP学习笔记之用户编程接口(NETCONN)
    七LWIP学习笔记之传输控制协议(TCP)
    六LWIP学习笔记之用户数据报协议(UDP)
    java实现二叉查找树
    线程的锁对象
    MAP
  • 原文地址:https://www.cnblogs.com/ljknlb/p/15883633.html
Copyright © 2020-2023  润新知