如何让我的Ninject模块干燥?

时间:2012-04-26 09:06:26

标签: c# ninject

我在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");
}

主要区别在于请求IDirectoryBuilder,其主要功能是通过使用IDirectory实施来根据配置设置确定文件的位置。

在上面的示例中,我返回了一个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 Factory方法创建IDirectoryBuilder,我看到的方式是我需要在我的代码库中分散ConfigurationManager个相关的调用。

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

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

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

2 个答案:

答案 0 :(得分:0)

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

简单的答案是,您为绑定表达式的前一个组件返回的内容(similar question)创建扩展方法。


在重新阅读您的问题时,我建议您查看Ninject.Extensions.Conventions哪些Bind扩展方法可以让您按照建议的方式执行大肆Bind 。如果不是,我建议评论和识别你认为它没有解决的位。

答案 1 :(得分:0)

根据Ruben的评论,这是我目前的解决方案。我做的一个瘦是使用约定的概念,因此检索我的配置设置变得更容易。这过滤了使用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"]
     };
 }