.net 核心依赖注入是不是支持 Lazy<T>
Posted
技术标签:
【中文标题】.net 核心依赖注入是不是支持 Lazy<T>【英文标题】:Does .net core dependency injection support Lazy<T>.net 核心依赖注入是否支持 Lazy<T> 【发布时间】:2017-12-09 14:40:14 【问题描述】:我正在尝试使用通用 Lazy 类来实例化具有 .net 核心依赖注入扩展的昂贵类。我已经注册了 IRepo 类型,但我不确定 Lazy 类的注册会是什么样子,或者它是否受支持。作为一种解决方法,我使用了这种方法http://mark-dot-net.blogspot.com/2009/08/lazy-loading-of-dependencies-in-unity.html
配置:
public void ConfigureService(IServiceCollection services)
services.AddTransient<IRepo, Repo>();
//register lazy
控制器:
public class ValuesController : Controller
private Lazy<IRepo> _repo;
public ValuesController (Lazy<IRepo> repo)
_repo = repo;
[HttpGet()]
public IActionResult Get()
//Do something cheap
if(something)
return Ok(something);
else
return Ok(repo.Value.Get());
【问题讨论】:
“实例化一个代价高昂的类”。为什么创建该类的成本很高?创建类不成本很高。他们的构造函数应该是simple,fast和reliable。 No (repository/context/...) 类应该在其构造函数中打开连接。 我无法控制的手段代价高昂。 【参考方案1】:这是另一种方法,它支持Lazy<T>
的泛型注册,因此可以延迟解析任何类型。
services.AddTransient(typeof(Lazy<>), typeof(Lazier<>));
internal class Lazier<T> : Lazy<T> where T : class
public Lazier(IServiceProvider provider)
: base(() => provider.GetRequiredService<T>())
【讨论】:
LazyLazy<T>
类,该类具有线程安全性,并且可以像内置类型一样完成工作。我认为可以肯定地说,Lazy<T>
在 99.9% 的用例中表现得足够好。
您可以自己编写,但这是一个简洁的解决方案。我的假设是 T 的昂贵初始化超过了与 Lazy 相关的任何成本。
这是一个很好的解决方案,直到有人写Laziest<T>
【参考方案2】:
您只需为创建Lazy<IRepo>
对象的工厂方法添加注册即可。
public void ConfigureService(IServiceCollection services)
services.AddTransient<IRepo, Repo>();
services.AddTransient<Lazy<IRepo>>(provider => new Lazy<IRepo>(provider.GetService<IRepo>));
【讨论】:
谢谢,我希望会有通用的惰性注册,但似乎不可能。至少 M$ DI 不会。 你可以自己写一个通用的辅助方法。【参考方案3】:在我看来,下面的代码应该可以完成工作(.net core 3.1)
services.AddTransient<IRepo, Repo>();
services.AddTransient(typeof(Lazy<>), typeof(Lazy<>));
【讨论】:
Avi 的好答案 这不会延迟解析服务,因为它依赖于Lazy<T>(T)
构造函数而不是Lazy<T>(Func<T>)
构造函数。
这是错误的。它不会被延迟加载。【参考方案4】:
Lazy 中要获取的服务将通过工厂注册方法 重新引入预期服务的new Lazy类型并使用 serviceProvider.GetRequiredService 为其实现提供。
services.AddTransient<IRepo, Repo>()
.AddTransient(serviceProvider => new Lazy<IRepo>(() => serviceProvider.GetRequiredService<IRepo>()));
【讨论】:
【参考方案5】:将服务注册为惰性
services.AddScoped<Lazy<AService>>();
services.AddScoped<Lazy<BService>>();
或者通过创建扩展
static class LazyServiceCollection
public static void AddLazyScoped<T>(this IServiceCollection services)
services.AddScoped<Lazy<T>>();
...
services.AddLazyScoped<AService>();
services.AddLazyScoped<BService>();
并使用它
[ApiController, Route("lazy")]
public class LazyController : ControllerBase
private readonly Lazy<AService> _aService;
private readonly Lazy<BService> _bService;
public LazyController(Lazy<AService> aService, Lazy<BService> bService)
_aService = aService;
_bService = bService;
[HttpGet("a")]
public ActionResult GetA()
_aService.Value.DoWork();
return new OkResult();
[HttpGet("b")]
public ActionResult GetB()
_bService.Value.DoWork();
return new OkResult();
结果
Init AService
AService Work
【讨论】:
以上是关于.net 核心依赖注入是不是支持 Lazy<T>的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 asp.net 核心中的依赖注入在工作单元模式中延迟注入存储库