简单注入器条件注入

8
假设我有两个控制器:ControllerA和ControllerB。这两个控制器都接受IFooInterface作为参数。现在我有两个IFooInterface的实现,FooA和FooB。我想在ControllerA中注入FooA,在ControllerB中注入FooB。这在Ninject中很容易实现,但由于Simple Injector性能更好,我要使用它。那么如何在Simple Injector中实现呢?请注意,ControllerA和ControllerB位于不同的程序集中,并且是动态加载的。谢谢。

2
这个问题在Stackoverflow上已经被提出多次,而我的职责就是质疑这样的设计。虽然这样的设计并不总是错误的,但你必须小心,不要违反Liskov替换原则。所以问题是,当ControllerA注入FooB时,它是否仍然能够正常工作,或者会出现故障?如果出现故障,那么你就违反了LSP,这意味着FooA和FooB应该各自实现一个不同的接口。 - Steven
@Steven 谢谢,你给了我一些思考的东西 :) - Davita
@Steven 再想一下,即使注入 FooB,ControllerA 仍然可以工作,从这个角度来看,我原则上可以缩短控制器的数量。问题在于,控制器使用从数据库中获取的一些数据来传递给 IFooInterface,对于 FooA 和 FooB 是不同的,因此它应该知道从哪个数据中获取。 - Davita
在Stackoverflow上讨论应用程序设计通常很困难,因为该网站有一些规则限制。如果你感兴趣的话,可以在simpleinjector.codeplex.com论坛上发起一个新的讨论,并提供一些具体的代码示例(而不是使用IFoo和Controller1这样的抽象名称)。在那个论坛上有多位开发者(像我和qujck)非常愿意与你讨论设计,并给予一些反馈。 - Steven
2个回答

17

从版本3开始,Simple Injector具有RegisterConditional方法

container.RegisterConditional<IFooInterface, FooA>(c => c.Consumer.ImplementationType == typeof(ControllerA));
container.RegisterConditional<IFooInterface, FooB>(c => c.Consumer.ImplementationType == typeof(ControllerB));
container.RegisterConditional<IFooInterface, DefaultFoo>(c => !c.Handled);

5
SimpleInjector文档将其称为基于上下文的注入。从版本3开始,您将使用RegisterConditional。但在2.8版本中,SimpleInjector尚未实现此功能,但文档包含实现此功能的工作代码示例,作为Container类的扩展。
使用这些扩展方法,您可以执行以下操作:
Type fooAType = Assembly.LoadFrom(@"path\to\fooA.dll").GetType("FooA");
Type fooBType = Assembly.LoadFrom(@"path\to\fooB.dll").GetType("FooB");
container.RegisterWithContext<IFooInterface>(context => {
    if (context.ImplementationType.Name == "ControllerA") 
    {
        return container.GetInstance(fooAType);
    } 
    else if (context.ImplementationType.Name == "ControllerB") 
    {
        return container.GetInstance(fooBType)
    } 
    else 
    {
        return null;
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接