【问题标题】: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/...) 类应该在其构造函数中打开连接。
  • 我无法控制的手段代价高昂。

标签: c# dependency-injection asp.net-core .net-core lazy-initialization


【解决方案1】:

这是另一种方法,它支持Lazy&lt;T&gt; 的泛型注册,因此可以延迟解析任何类型。

services.AddTransient(typeof(Lazy<>), typeof(Lazier<>));

internal class Lazier<T> : Lazy<T> where T : class
{
    public Lazier(IServiceProvider provider)
        : base(() => provider.GetRequiredService<T>())
    {
    }
}

【讨论】:

  • Lazy 太重了,我建议使用更轻的版本。
  • @AkashKava 你指的是哪个更轻的替代品?
  • @Akash 请展示如何“轻松”编写一个“更轻”的Lazy&lt;T&gt; 类,该类具有线程安全性,并且可以像内置类型一样完成工作。我认为可以肯定地说,Lazy&lt;T&gt; 在 99.9% 的用例中表现得足够好。
  • 您可以自己编写,但这是一个简洁的解决方案。我的假设是 T 的昂贵初始化超过了与 Lazy 相关的任何成本。
  • 这是一个很好的解决方案,直到有人写Laziest&lt;T&gt;
【解决方案2】:

您只需为创建Lazy&lt;IRepo&gt; 对象的工厂方法添加注册即可。

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&lt;T&gt;(T) 构造函数而不是Lazy&lt;T&gt;(Func&lt;T&gt;) 构造函数。
  • 这是错误的。它不会被延迟加载。
【解决方案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
    

    【讨论】:

      猜你喜欢
      • 2018-12-14
      • 2019-02-16
      • 1970-01-01
      • 2021-03-02
      • 1970-01-01
      • 1970-01-01
      • 2023-01-04
      • 2019-11-18
      • 2021-02-28
      相关资源
      最近更新 更多