我有类似于以下的东西:
interface IOuter { ... }
interface IInner { ... }
class Outer : IOuter {
public Outer(IInner inner) { ... }
}
class InnerA : IInner { ... }
class InnerB : IInner { ... }
我需要根据命令行上传递的选项将InnerA
或InnerB
注入到Outer
的构造函数中。
根据我的调查,我有两个选择:
使用条件绑定:CCD_ 4,并且对于CCD_ 5具有类似的结合。
使用元数据:与
Bind<IInner>().To<InnerA>().WithMetadata("option", "useA")
绑定,与kernel.Get<IOuter>(metadata => metadata.Has("option") && metadata.Get<string>("option") == option)
解析
方法#1有效,但我将绑定放在一个模块中,该模块不应该作为全局变量访问命令行option
。理想情况下,模块应该只依赖于解析过程中传递的上下文信息。
这给我留下了方法#2,但它不起作用,因为显然元数据只适用于解析当前接口,在我的情况下是IOuter
。当尝试解析Outer
(即IInner
(的依赖关系时,它不适用,所以我从Ninject收到一个错误,它无法激活IOuter
(没有匹配的绑定可用(。
第三种选择是使用kernel.Get<IOuter>(new ConstructorArgument("inner", ctx => ctx.Kernel.Get<IInner>(metadata => ...)))
,但它过于手动和冗长。此外,如果链中有多个依赖项需要类似的逻辑,则会变得难以处理。
是否有一种方法可以根据解析根对象时传递的元数据有条件地绑定依赖项(可能是依赖链中的几个级别(,而不依赖于访问全局配置/选项?
我需要根据命令行上传递的选项将InnerA或InnerB注入Outer的构造函数。
换句话说,所选组件在应用程序的生存期内不会发生更改。
只需这样做:
if (commandLineArg) {
Bind<IInner>().To<InnerA>();
} else {
Bind<IInner>().To<InnerB>();
}