【问题标题】:Simple Injector decoration with additional dependency带有额外依赖的简单注入器装饰
【发布时间】:2015-09-05 23:50:00
【问题描述】:

我有一个装饰器 SomethingLoggerDecorator,它应该用日志记录装饰 ISomething 实例:

public class SomethingLoggerDecorator : ISomething
{
    private readonly ISomething decoratee;
    private readonly ILogger logger;

    public SomethingLoggerDecorator(ISomething decoratee, ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }

    public void DoSomething()
    {
        this.logger.Info("Doing Something");
        this.decoratee.DoSomething();
    }

    public void DoSomethingElse(string withThis)
    {
        this.logger.Info("Doing Something Else with " + withThis);
        this.decoratee.DoSomethingElse(withThis);
    }
}

如何使用 Simple Injector 用 SomethingLoggerDecorator 装饰 ISomething 的实例,并使用静态工厂方法 LogManager.GetLogger(decoratee.GetType())ILogger 的实例注入到每个装饰器中,其中 decoratee 是要执行的实际实例被装饰?此外,注入的ILoggerSomethingLoggerDecorator 的生命周期应始终与被装饰者的生命周期相匹配。

【问题讨论】:

    标签: c# logging dependency-injection decorator simple-injector


    【解决方案1】:

    在 Simple Injector 中有多种方法可以做到这一点。

    首先,您可以让装饰器的构造函数依赖于DecoratorContext 类。 DecoratorContext 包含有关装饰器的上下文信息。它包含诸如包装装饰器的类型和被装饰的实际实现的类型(真实实例)等信息。所以你的装饰器可能如下所示:

    public class SomethingLoggerDecorator : ISomething
    {
        private readonly ISomething decoratee;
        private readonly DecoratorContext context;
    
        public SomethingLoggerDecorator(ISomething decoratee, DecoratorContext context)
        {
            this.decoratee = decoratee;
            this.context = context;
        }
    
        public void DoSomething()
        {
            var logger = LogManager.GetLogger(this.context.ImplementationType);
            logger.Info("Doing Something");
            this.decoratee.DoSomething();
        }
    }
    

    使用这个DecoratorContext 类的缺点是你的装饰器需要依赖于简单注入器,这基本上意味着你必须将装饰器移动到你的Composition Root 中以防止你的应用程序依赖于DI 库。你可以找到更多关于使用这个DecoratorContexthere的信息。

    另一种选择是使您的装饰器通用,并为可以生成正确装饰器的RegisterDecorator 重载之一提供装饰器类型工厂。例如:

    public class SomethingLoggerDecorator<TImplementation> : ISomething
    {
        private readonly ISomething decoratee;
    
        public SomethingLoggerDecorator(ISomething decoratee)
        {
            this.decoratee = decoratee;
        }
    
        public void DoSomething()
        {
            var logger = LogManager.GetLogger(typeof(TImplementation));
            logger.Info("Doing Something");
            this.decoratee.DoSomething();
        }
    }
    

    或可选:

    public class SomethingLoggerDecorator<TImplementation> : ISomething
    {
        private readonly ISomething decoratee;
        private readonly ILogger<TImplementation> logger;
    
        public SomethingLoggerDecorator(ISomething decoratee, ILogger<TImplementation> logger)
        {
            this.decoratee = decoratee;
            this.logger = logger;
        }
    
        public void DoSomething()
        {
            this.logger.Info("Doing Something");
            this.decoratee.DoSomething();
        }
    }
    

    使用这两种实现,您可以按如下方式注册装饰器:

    container.RegisterDecorator(typeof(ISomething),
        c => typeof(SomethingLoggerDecorator<>).MakeGenericType(c.ImplementationType),
        Lifestyle.Transient,
        predicate: c => true);
    

    使用第二个实现,您会将问题稍微转移到通用的ILogger&lt;T&gt; 抽象上,但实现可能如下所示:

    public class Log4netAdapter<T> : ILogger<T>
    {
        public void Log(LogEntry entry) {
            var logger = LogManager.GetLogger(typeof(T));
            // TODO: log
        }
    }
    

    【讨论】:

    • 在你的第一个代码中 sn -p this.context.ImplementationType.GetType() GetType() 必须被删除。已经是类型了。
    猜你喜欢
    • 2017-02-05
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 2018-08-07
    • 2016-02-11
    • 2012-11-06
    相关资源
    最近更新 更多