使用Ninject注入实现相同接口的不同类

Set*_*eth 11 c# ninject

我正在实现构建器设计模式,以构建要在WPF UI上显示的不同类型的图形对象.我使用Ninject作为我的IOC容器.但是,我试图找到一个优雅的可扩展解决方案.

我有一个ChartDirector对象IChartBuilder作为依赖.我也有TemperatureChartBuilderThresholdChartBuilder实现IChartBuilder.我想无论是注入TemperatureChartBuilderThresholdChartBuilderChartDirector取决于被解雇或根据客户端调用的事件.我在下面用代码说明了我的问题.

// ChartDirector also depends on this
kernel.Bind<IExample>().To<Example>();

// when called in Method X...
kernel.Bind<IChartBuilder>().To<TemperatureChartBuilder>();

// when called in Method Y...
kernel.Bind<IChartBuilder>().To<ThresholdChartBuilder();

// TemperatureChartBuilder is a dependency of ChartDirector, need a way to dynamically
// allocate which binding to use.
var director = kernel.Get<ChartDirector>();

// without Ninject I would do
var director = new ChartDirector(new TemperatureChartBuilder);

// or
var director = new ChartDirector(new ThresholdChartBuilder);
Run Code Online (Sandbox Code Playgroud)

编辑:

再加上Gary的回答,并注意到ChartDirector有另一个依赖的轻微编辑,我现在想做这样的事情:

var director = kernel.Get<ChartDirector>().WithConstructorArgument(kernel.Get<IChartBuilder>("TemperatureChart"));
Run Code Online (Sandbox Code Playgroud)

这样的事情可能吗?

Eri*_*sch 15

如果你只是计划使用服务位置,就像在你的例子中一样,那么根据Garys的回答,命名绑定工作正常.

但是,更好的方法是使用构造函数注入,并使用属性.例如,来自ninject wiki:

Bind<IWeapon>().To<Shuriken>().Named("Strong");
Bind<IWeapon>().To<Dagger>().Named("Weak"); 
Run Code Online (Sandbox Code Playgroud)

...

class WeakAttack {
    readonly IWeapon _weapon;
    public([Named("Weak")] IWeapon weakWeapon)
        _weapon = weakWeapon;
    }
    public void Attack(string victim){
        Console.WriteLine(_weapon.Hit(victim));
    }
}
Run Code Online (Sandbox Code Playgroud)

根据你对加里的评论,你(奇怪的是)磕磕绊绊地走进了几个小时前我问过的问题.请参阅Remo的答案:使用WithConstructorArgument并创建绑定类型

您可以使用When condition来定义何时创建正确的实例.


Gar*_*y.S 9

我建议使用Contextual绑定(专门命名绑定)来实现这一点.这样你可以做类似的事情:

// called on app init
kernel.Bind<IChartBuilder>().To<TemperatureChartBuilder>().Named("TempChartBuilder");   
kernel.Bind<IChartBuilder>().To<ThresholdChartBuilder().Named("ThreshChartBuilder");

// method X/Y could both call method Z that grabs the correct chart director
var director = new ChartDirector(kernel.Get<IChartBuilder>("TempChartBuilder"));
Run Code Online (Sandbox Code Playgroud)

其中"TempChartBuilder"可以是一个变量,告诉ninject要解析哪个绑定.因此,您可以即时解决动态绑定,但可以预先定义所有绑定.通常,IOC容器存储在应用程序域级别,只需定义一次.可能存在需要动态绑定的特定情况,但这些情况应该很少见.

有关上下文绑定的更多信息:https://github.com/ninject/ninject/wiki/Contextual-Binding