2014-07-17 98 views
0

我有一個接口,讓我們稱之爲IConfig。 接下來,我有一些類亞軍。 Runner在構造函數中使用IConfig和其他一些參數。使用任務和Ninject進行Paralellization

但是,當我有多個IConfig實例,每個定義一個運行,我不能GetAll賽跑者,因爲我得到一個ActivationException「多個匹配的綁定可用」。

我猜這是因爲這不是StandardKernel期望的工作方式。 我想要的是內核爲每個綁定的IConfig創建一個Runner的新實例。

有沒有辦法使用ninject來做到這一點,而不必手動創建實例?我想要什麼

示例代碼:什麼,我必須做的,而不是

Task.WaitAll(kernel.GetAll<IRunner>().Select(r => Task.Run((Action)r.Run)).ToArray()); 

示例代碼:

IControl control = kernel.Get<IControl>(); 
Task[] runners = kernel.GetAll<IConfig>() 
    .Select(c => new Runner(kernel.Get<IService1>(), kernel.Get<IService2>(), c, control)) 
    .Select(r => Task.Run((Action)r.Run)) 
    .ToArray(); 
Task.WaitAll(runners); 

回答

2

沒有出來這樣的情景內置支持。 雖然有很多方法可以實現你想要的。

因此,讓我們開始

public class Runner 
{ 
    public Runner(IService1 service1, IService2 service2, IConfig config, IControl control) 
    { 
    } 

    public void Run() 
    { 
    } 
} 

解決方案1 ​​: 我們將使用一個.ToFactory()結合創建亞軍 - 所具有的依賴注入。

public interface IRunnerFactory 
{ 
    // all parameters are passed to the constructor of Runner 
    // parameters are matched by name, so make sure they match! ctor(IConfig myconfig) won't work, it must be ctor(IConfig config). 
    // but of course you can add more parameters to the ctor and have them injected: ctor(IService1 foo, IControl bar, IConfig config, IService2 foo2) 
    Runner Create(IConfig config); 
} 

public class AllRunner 
{ 
    private readonly IList<IConfig> runnerConfigurations; 
    private readonly IRunnerFactory runnerFactory; 

    public AllRunner(IList<IConfig> runnerConfigurations, IRunnerFactory runnerFactory) 
    { 
     this.runnerConfigurations = runnerConfigurations; 
     this.runnerFactory = runnerFactory; 
    } 

    public void RunAll() 
    { 
     Task[] runners = this.runnerConfigurations 
      .Select(this.runnerFactory.Create) 
      .Select(runner => Task.Run((Action) runner.Run)) 
      .ToArray(); 

     Task.WaitAll(runners); 
    } 
} 


// you could also use .InNamedScope() or maybe InParentScope() or InCallScope() -- see the NamedScope extension! 
kernel.Bind<IControl>().To<Control>().InSingletonScope(); 

// implementation is auto generated. 
kernel.Bind<IRunnerFactory>().ToFactory(); 

kernel.Bind<IConfig>().To<Config1>(); 
kernel.Bind<IConfig>().To<Config2>(); 
kernel.Bind<IConfig>().To<Config3>(); 

注:


解決方案2

我們將延長解決方案1和使用供應商/ .ToProvider()結合,所以我們可以注入IReadOnlyCollection<Runner>

public class RunnersProvider : Provider<IReadOnlyCollection<Runner>> 
{ 
    private readonly IList<IConfig> runnerConfigurations; 
    private readonly IRunnerFactory runnerFactory; 

    public RunnersProvider(IList<IConfig> runnerConfigurations, IRunnerFactory runnerFactory) 
    { 
     this.runnerConfigurations = runnerConfigurations; 
     this.runnerFactory = runnerFactory; 
    } 

    protected override IReadOnlyCollection<Runner> CreateInstance(IContext context) 
    { 
     return this.runnerConfigurations 
      .Select(this.runnerFactory.Create) 
      .ToArray(); 
    } 
} 


kernel.Bind<IReadOnlyCollection<Runner>>().ToProvider<RunnersProvider>(); 

然後你可以做

IResolutionRoot.Get<IReadOnlyCollection<Runner>>() 

,或者也注入IReadOnlyCollection<Runner>成男星 - 但不是IEnumerable<Runner>或任何其他類型的,因爲你明確地結合IReadOnlyCollection<Runner>,而不是利用ninject的多結合/多次注射功能。

你也需要注意的是kernel.Bind<IEnumerable<Foo>>()(同樣適用於IList<>ICollection<>foo[] - 所有類型ninject支持自動多注射液)是脆。您可以執行kernel.Get<IEnumerable<Foo>>(),但不能注入相同類型,因爲如果將它用於ctor-injection,ninject會嘗試找到與Foo匹配的綁定,而不是IEnumerable<Foo>(多注入支持)。

+0

這看起來很有希望,但我需要處理一下這一點^ _^ 在相關的不是,IConfig對象是使用foreach從App.config轉換字​​符串添加的; 的foreach(IConfig下在Config.Select(JSON )) 綁定().ToConstant(C); 有沒有更好的辦法做到這一點呢? 以上配置屬性只是Properties.Settings.Default的包裝...由 –

+0

你應該考慮不是在所有綁定'IConfig'的方式。代替綁定'IConfigReader'與方法'的IEnumerable ReadConfig()'。 – BatteryBackupUnit

+0

當我嘗試解決方案與IConfigReader方法結合使用後,當我調用configs.Select(factory.Create).ToList() –