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

  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";
}

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

 

 

 

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

 

 

posted @ 2022-02-11 16:03  刘靖凯  阅读(145)  评论(0编辑  收藏  举报