2011-12-21 122 views
11

我正在實現構建器設計模式,以構建不同種類的圖形對象以在WPF UI上顯示。我使用Ninject作爲我的IOC容器。但是,我試圖找到一個優雅的可擴展解決方案。使用Ninject注入實現相同接口的不同類使用Ninject

我有一個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); 

編輯:

加上加里的答覆,並注意到有輕微編輯ChartDirector中有另一個依賴,我現在想要做這樣的事情:

var director = kernel.Get<ChartDirector>().WithConstructorArgument(kernel.Get<IChartBuilder>("TemperatureChart")); 

是這樣的可能?

回答

8

我會建議使用上下文綁定(具體命名綁定)來完成此操作。這樣,你可以這樣做:

// 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")); 

其中「TempChartBuilder」可能是告訴ninject其結合來解決一個變量。因此,您可以即時解決問題,但可以在前面定義所有綁定。通常,IOC容器存儲在應用程序域級別,只需定義一次即可。在某些情況下,您可能需要動態綁定,但這些應該很少。

在上下文綁定更多信息:https://github.com/ninject/ninject/wiki/Contextual-Binding

+0

+1非常有幫助。在原始問題中我沒有提到的一件事是ChartBuilder在App初始化期間指定了其他依賴項,因此當我調用kernel.Get 時,ninject會自動注入其他所需的依賴項。那麼有沒有一種方法可以用'kernel.Get '來完成你的建議,併爲每個特定的Get注入正確的chartbuilder? – Seth 2011-12-21 05:40:13

+0

@Seth - 您可能想要查看創建兩個不同的ninject模塊,其中只包含要解析的特定綁定 - https://github.com/ninject/ninject/wiki/Modules-and-the-Kernel。我還會看看ninject提供的動態工廠/提供者模型 - https:// github。com/ninject/ninject/wiki/Providers,-Factory-Methods-and-the-Activation-Context – 2011-12-21 05:49:47

+0

你可以看看我的編輯 - 我不確定你最近評論中的建議是否解決了我的問題的最後一個組成部分。 。感謝您迄今爲止的幫助:) – Seth 2011-12-21 06:12:52

15

如果你只是打算使用服務的位置,在你的例子,然後命名綁定做工精細,按Garys答案。

但是,更好的方法是使用構造函數注入並使用屬性。對於爲例,從ninject維基:

Bind<IWeapon>().To<Shuriken>().Named("Strong"); 
Bind<IWeapon>().To<Dagger>().Named("Weak"); 

...基於加里您的評論

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

,你(很奇怪)跌進類似於我問一個問題關於領土幾個小時前。請參閱Remo的回答:Using WithConstructorArgument and creating bound type

您將使用When條件來定義何時創建正確的實例。