2012-04-26 56 views
0

我在我的Ninject模块中重复了几次以下的代码。我可以使用哪些方法和技术来减少这些重复的代码?请求IDirectoryBuilder,其主要功能是确定通过使用IDirectory实施的基础上配置设置的文件的位置时发生如何让我的Ninject模块干燥?

public override void Load() 
{ 
    Bind<IDataReader<IList<Price>>>() 
     .To<PricesDataReader>().Named("ValDatePrices"); 
    Bind<IDataConnection<IList<PricesCsvRecord>>>() 
     .To<PricesXLConnection>().WhenParentNamed("ValDatePrices") 
     .Named("ValDatePricesXLConnection"); 
    Bind<IDirectoryBuilder>() 
     .ToMethod(DefaultValDatePricesDirectory) 
     .WhenParentNamed("ValDatePricesXLConnection"); 

    Bind<IDataReader<IList<Price>>>() 
     .To<PricesDataReader>().Named("EDDatePrices"); 
    Bind<IDataConnection<IList<PricesCsvRecord>>>() 
     .To<PricesXLConnection>().WhenParentNamed("EDDatePrices") 
     .Named("EDDatePricesXLConnection"); 
    Bind<IDirectoryBuilder>() 
     .ToMethod(DefaultEDDatePricesDirectory) 
     .WhenParentNamed("EDDatePricesXLConnection"); 
} 

的主要区别。

在上面的例子中,我返回一个DefaultDirectoryBuilder,但是我有几个其他的实现(请参阅下面的EdNrrDirectoryBuilder方法)。

public IDirectoryBuilder DefaultValDatePricesDirectory(IContext arg) 
{ 
    return new DefaultDirectoryBuilder(
     ConfigurationManager.AppSettings["VALDATE_PRICES_DIR"], 
     ConfigurationManager.AppSettings["VALDATE_PRICES_FILENAME"]); 
} 

public IDirectoryBuilder DefaultEDDatePricesDirectory(IContext arg) 
{ 
    return new DefaultDirectoryBuilder(
     ConfigurationManager.AppSettings["EDDATE_PRICES_DIR"], 
     ConfigurationManager.AppSettings["EDDATE_PRICES_FILENAME"]); 
} 

public IDirectoryBuilder EdNrrDirectoryBuilder(IContext arg) 
{ 
    return new ExternalDirectoryBuilder(
     ValuationDate, 
     ConfigurationManager.AppSettings["NRRDATE_DIR"], 
     ConfigurationManager.AppSettings["NRRDATE_PRICES_FILENAME"]); 
} 

我的问题是我需要我的配置文件的值。现在,所有与配置相关的请求在我的Ninject模块中都是有限的。

如果我使用Ninject工厂方法创建IDirectoryBuilder s,我看到的方式是我需要将ConfigurationManager相关的调用分散在我的代码库中。

如果我使用Ninject Provider方法,我将需要所有实现IDirectoryBuilder的提供者,并且还更新了我的构造函数和IDataConnection的实现。我的代码现在看起来像(不是非常干燥,类似于我目前的方法)。

Bind<IDirectoryBuilder>().ToProvider<DefaultDirectoryBuilderProvider>() 
    .WhenParentNamed("EDDatePricesXLConnection") 
    .WithConstructorArgument("baseDir", "someConfigValue") 
    .WithConstructorArgument("fileName", "someOtherConfigValue"); 

我的代码具有目前一个非常一致的依赖链(使用NamedArguments):ICalculator - >IDataReader - >IDataConnection - >IDirectoryBuilder - 这使我相信,必须有某种方式来重复创建这条产业链而不必重复设置代码 - 我似乎无法弄清楚。还有一个额外的限制,因为我经常需要两个相同的依赖链实例 - 唯一的区别是配置值不同。

+0

参见http://stackoverflow.com/questions/10344568/binding-recurring-connection-string-constructor-parameters-using-di – 2012-04-27 07:36:41

回答

0

基于鲁本的评论,这是我目前的解决方案。我做的一个细节是使用约定的概念,因此检索我的配置设置变得更容易。这通过使用Ninject Named参数的大多数其他代码进行过滤。

public void Load(){ 
    BindDependencies<IDataReader<IList<Price>>, PricesDataReader 
     , IDataConnection<IList<PricesCsvRecord>>, PricesXLConnection 
     , DefaultDirectoryBuilder> 
     ("ValDatePrices"); 

    BindDependencies<IDataReader<IList<Price>>, PricesDataReader 
     , IDataConnection<IList<PricesCsvRecord>>, PricesXLConnection 
     , DefaultDirectoryBuilder> 
     ("EDDatePrices"); 
     // etc etc 
} 

public void BindDependencies< 
    TReaderBase, TReaderImpl, 
    TDataConnectionBase, TDataConnectionImpl, 
    TDirectoryBuilderFactoryImpl> 
    (string baseName) 
     where TReaderImpl : TReaderBase 
     where TDataConnectionImpl : TDataConnectionBase 
{ 
    DirectoryBuilderInfo dirInfor = GetSettings(baseName); 

    Bind<TReaderBase>() 
      .To(typeof(TReaderImpl)) 
      .Named(baseName); 
    Bind<TDataConnectionBase>().To(typeof(TDataConnectionImpl)) 
      .WhenParentNamed(baseName) 
      .Named(baseName + "XLConnection"); 
    Func<IDirectoryBuilder> directoryBuilder = CreateDirectoryBuilderFunc<TDirectoryBuilderFactoryImpl>(dirInfor); 

    Bind<IDirectoryBuilder>() 
      .ToMethod(d => directoryBuilder()) 
      .WhenParentNamed(baseName + "XLConnection"); 
    } 

private Func<IDirectoryBuilder> CreateDirectoryBuilderFunc<TDirectoryBuilderFactoryImpl>(DirectoryBuilderInfo dirInfor) 
{ 
    Func<IDirectoryBuilder> directoryBuilder = 
     () => CreateDefaultDirectoryBuilder(dirInfor.BaseDirectory, dirInfor.FileName); 

    if (typeof(TDirectoryBuilderFactoryImpl) == typeof(RiskDirectoryBuilderFactory)) 
    { 
     directoryBuilder = 
     () => CreateRiskDirectoryBuilder(ValuationDate, dirInfor.BaseDirectory, dirInfor.FileName); 
    } 
    return directoryBuilder; 
} 

private DirectoryBuilderInfo GetSettings(string baseName) 
{ 
    var settingsName = baseName.ToUpperInvariant(); 
    return new DirectoryBuilderInfo() 
    { 
     BaseDirectory = ConfigurationManager.AppSettings[settingsName + "_DIR"], 
     FileName = ConfigurationManager.AppSettings[settingsName + "_FILENAME"] 
    }; 
} 
+0

看起来不错。有一件事:依赖倒置原则: - 你应该将'Func '传入'BindDependencies'中,而不必使用特殊情况调用辅助函数。然后做一个超载,通过默认的并在大多数情况下使用它。如果你还没有获得manning.com/seemann – 2012-05-03 10:31:01

0

没有理由依赖任何Ninject具体技术(尽管在某些情况下,Provider可能是合适的(example of a provider here)。

简单的答案是,你创造了什么绑定的前面部分的扩展方法表达式返回(similar question)。


在重新阅读你的问题,我建议你看Ninject.Extensions.Conventions其中HASS很多Bind扩展方法,让你做bullk在T Bind英格斯他建议你的方式。如果不是,我会建议评论和识别你觉得它没有解决的位。

+0

喜鲁本 - 可以请你提供一个简单的例子或者一些指导开始在我的情况下使用扩展。我已经阅读了Wiki,但没有什么真正打击我作为一个可行的解决方案。 – Ahmad 2012-05-02 07:41:42

+0

@Ahmad不是在说什么地球震碎。步骤1只是一个方法,它包含了每个属于3个绑定的块。然后在那之后,如果剩余时间/重复序列重复,则制作一个扩展方法,将两者连接在一起。在EdNrrDirectoryBuilder中使用'ValuationDate'表明事情并不完全一致。经过反思,很难说您的配置顺序是否足够规范,以便适用惯例。将反馈删除此答案很快,因为您的问题太宽泛,无法获得干净的答案。 – 2012-05-02 11:29:07

+0

我已经根据您的意见创建了解决方案 - http://stackoverflow.com/a/10429406/268667 – Ahmad 2012-05-03 10:21:35