代码之家  ›  专栏  ›  技术社区  ›  Raik

基于简单注射器的生活方式注册实现

  •  1
  • Raik  · 技术社区  · 9 年前

    我已经尝试过这样的东西:

    container.RegisterConditional(typeof(ILogger),
        x => typeof(NContextLogger<>).MakeGenericType(
            x.Consumer.ImplementationType),
        Lifestyle.Scoped,
        x => container.GetCurrentExecutionContextScope() != null);
    
    container.RegisterConditional(typeof(ILogger),
        x => typeof(NLogger<>).MakeGenericType(x.Consumer.ImplementationType),
        Lifestyle.Singleton,
        x => container.GetCurrentExecutionContextScope() == null);
    

    问题在于创建的任何实例 NContextLogger<> .因为当它创建 NLogger<> 这是单例,简单注入器不尝试创建 NContextLogger .

    1 回复  |  直到 4 年前
        1
  •  3
  •   Steven    4 年前

    提供给的谓词 RegisterConditional 不能用于运行时决策,因为谓词的结果被缓存并烧录到表达式树和编译委托中。该 GetCurrentExecutionContextScope() Lifestyle.Scoped.GetCurrentScope(Container) 然而,这是一个运行时决定。

    在构建对象图期间,不应基于运行时条件做出决策(原因与 runtime data shouldn't be injected into components ).

    与其在构建对象图期间根据运行时条件做出决策,不如将这些决策推迟到构建对象图之后。最明显的方法是引入代理类:

    public sealed class ProxyLogger<T> : ILogger
    {
        private readonly Container container;
    
        public ProxyLogger(Container container) {
            this.container = container;
        }
    
        // Implement ILogger method(s)
        public void Log(string message) => Logger.Log(message);
        
        private ILogger Logger =>
            Lifestyle.Scoped.GetCurrentScope(container) == null
                ? container.GetInstance<NLogger<T>>()
                : container.GetInstance<NContextLogger<T>>();
    }
    

    使用此代理类,您可以进行以下注册以满足您的要求:

    container.RegisterConditional(typeof(ILogger),
        c => typeof(ProxyLogger<>).MakeGenericType(
            x.Consumer.ImplementationType),
        Lifestyle.Singleton,
        c => true);
        
    container.Register(typeof(NLogger<>), typeof(NLogger<>),
        Lifestyle.Singleton);
    container.Register(typeof(NContextLogger<>), typeof(NContextLogger<>),
        Lifestyle.Singleton);