如何使用简单的注入器在运行时更改依赖注册?

时间:2012-08-23 02:25:33

标签: c# .net dependency-injection ioc-container simple-injector

我正在使用Simple Injector IoC框架,我希望能够在运行时更改依赖项注册。例如,我有两个接口A的实现BI。实现A在app start注册,但是根据运行时可以更改的某个标志,我想切换实现。我们目前正在执行我们OnActionExecuting的{​​{1}}事件,我们所有的控制器都继承了该事件。以下是我想要做的示例代码。

BaseController

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:9)

如果IsRuntimeFlag是配置值(因此在应用程序的生命周期内无法更改),您可以按如下方式进行注册:

if (IsRuntimeFlag)
{
    container.Register<I, A>();
}
else
{
    container.Register<I, B>();
}

或同等地:

container.Register(typeof(I), IsRuntimeFlag ? typeof(A) : typeof(B));

如果值在应用程序的生命周期内发生变化,代理或composite处理调度到正确的实例是正确的解决方案:

public sealed class RuntimeFlagIComposite : I
{
    private readonly A a;
    private readonly B b;

    public RuntimeFlagIComposite(A a, B b) {
        this.a = a;
        this.b = b;
    }

    void I.Method() => this.Instance.Method();

    private I Instance => IsRuntimeFlag ? this.a : this.b;
}

由于复合直接取决于AB,因此您只需按以下方式注册:

container.Register<I, RuntimeFlagIComposite>();

AB的生命周期与瞬态不同(每个请求的新实例)时,您还应注册它们。例如:

container.Register<A>(Lifestyle.Singleton);
container.Register<B>(Lifestyle.Scoped);

您还可以让复合体依赖于I抽象本身而不是具体的AB实现:

public class RuntimeFlagIComposite : I
{
    private I a;
    private I b;

    public RuntimeFlagIComposite(I a, I b)
    {
        this.a = a;
        this.b = b;
    }
}

取决于I抽象,使这个类更灵活,更可测试。但这确实意味着你需要注册它有点不同:

container.Register<I, RuntimeFlagIComposite>();

container.RegisterConditional<I, A>(c => c.Consumer.Target.Name == "a");
container.RegisterConditional<I, B>(c => c.Consumer.Target.Name == "b");