【问题标题】:Simple Injector decoratee factory in scoped proxy decorators作用域代理装饰器中的简单注入器装饰工厂
【发布时间】:2017-07-11 11:03:05
【问题描述】:

关于docs of SimpleInjector 将装饰器模式与装饰工厂一起使用,我遇到了以下问题。

假设我有一个类似的ThreadScopedCommandHandlerProxy<T>,具有以下实现:

public class LifetimeScopeCommandHandlerProxy<T> : ICommandHandler<T>
{
    private readonly IScopeStarter _scopeStarter;
    private readonly IServiceFactory<ICommandHandler<T>> _decorateeFactory;

    public LifetimeScopeCommandHandlerProxy(
        IScopeStarter scopeStarter,
        IServiceFactory<ICommandHandler<T>> decorateeFactory)
    {
        _scopeStarter = scopeStarter;
        _decorateeFactory = decorateeFactory;
    }

    [DebuggerStepThrough]
    public void Handle(T command)
    {
        using (_scopeStarter.BeginScope())
        {
            ICommandHandler<T> handler = _decorateeFactory.CreateInstance();
            handler.Handle(command);
        }
    }
}

通常我会在代理中注入 Func&lt;ICommandHandler&lt;T&gt;&gt;,但我想从中抽象出来并创建一个 IServiceFactory,它在内部只是这样做:

public class SimpleInjectorServiceFactory<TService> : IServiceFactory<TService>
{
    private readonly Func<TService> _factory;

    public SimpleInjectorServiceFactory(Func<TService> factory)
    {
        _factory = factory;
    }

    public TService CreateInstance()
    {
        return _factory.Invoke();
    }
}

您可以通过查看类名来了解其背后的原因,这是一个 Simple Injector 特定的工厂。现在我知道使用这样的工厂抽象会引入代码异味。但在这种情况下,它只能用作基础设施组件。这个想法是我希望代理可以被多个库/应用程序使用,因此使其成为应用程序架构中的通用组件。

现在问题当然是,我得到以下异常:

For the container to be able to use LifetimeScopeCommandHandlerProxy<TCommand>
as a decorator, its constructor must include a single parameter
of type ICommandHandler<TCommand> (or Func<ICommandHandler<TCommand>>)
- i.e. the type of the instance that is being decorated.
The parameter type ICommandHandler<TCommand> does not currently exist
in the constructor of class LifetimeScopeCommandHandlerProxy<TCommand>.'

现在这个异常消息非常清楚,我理解这背后的原因。但是,我还是想知道是否可以绕过异常?

【问题讨论】:

    标签: c# simple-injector


    【解决方案1】:

    我想知道是否可以绕过异常

    没有办法做到这一点,除非完全绕过并重新实现 Simple Injector 的装饰器子系统。

    Simple Injector 的子系统通过包装一个装饰器来拦截服务的构建。尽管装饰器子系统会将装饰器及其依赖项的创建外包回 Simple Injector 的核心基础设施,但它将覆盖捕获装饰实例的依赖项的创建。这种行为在装饰器子系统中是硬编码的,这意味着不可能将类型的被装饰者移动到装饰器的子类中。

    【讨论】:

    • 明确的答案,但不幸的是。你会反对我试图引入的抽象吗?
    • @QuantumHive:我会的。对我来说,它似乎没有任何好处,当将 ICommandHandler&lt;T&gt; 抽象移出装饰器时,使用 IServiceFactory 来解析被装饰者变得非常不直观。 IServiceFactory 似乎是您的典型服务定位器,因此有人可能不会期望从它的解析会返回服务的“剥离”版本(剥离一个或多个装饰器)。
    • 我同意。如果您想让代理成为架构的可重用、外部和通用组件,您会给出什么建议?因为Func&lt;T&gt; decorateeFactory 似乎以类似的方式不直观,因为类型没有显示实际意图(除了参数的名称,它与IServiceFactory 相同)。此外,当不使用 Simple Injector 作为 DI 供应商时,可重用组件可能会引入可用性问题。这似乎是一种隐含的供应商锁定,对吧?
    • @QuantumHive:您无法真正解决这种类型的供应商锁定问题。您被 Simple Injector 锁定是因为它独特且引人注目的功能,而不是因为您依赖于特定于框架的类型。您应该以对您最有意义的方式设计系统,并相应地选择您的库和框架。这似乎是你所做的。不过,如果您找到另一个支持此功能的库,您仍然可以交换。如果没有 DI 容器(又名 Pure DI),您可以总是做到这一点。明智地选择你的工具。
    • 虽然这个名字对某些人来说可能不是那么直观,但这种设计可以被认为是一种模式或模板。您可能需要就此向其他开发人员进行教育。尽管如此,很难想象用不同的方式来设计类似的装饰器,而且仅依赖于基本的 .NET 类型实际上是你能得到的最好的东西,因为它可以防止依赖于特定于工具的抽象和类型。
    猜你喜欢
    • 2012-11-06
    • 2020-10-04
    • 1970-01-01
    • 2016-10-20
    • 2017-09-18
    • 2016-02-08
    • 2017-07-06
    • 2015-09-05
    • 1970-01-01
    相关资源
    最近更新 更多