注入一接口多实例,小心有坑
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";
}
调用三个子实例的结果,每次只实例化要使用的子类,节省开销。
想要更快更方便的了解相关知识,可以关注微信公众号
****欢迎关注我的asp.net core系统课程****
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524
《asp.net core精要讲解》 https://ke.qq.com/course/265696
《asp.net core 3.0》 https://ke.qq.com/course/437517
《asp.net core项目实战》 https://ke.qq.com/course/291868
《基于.net core微服务》 https://ke.qq.com/course/299524