使用依赖注入将配置代码保留在逻辑代码之外的方法

Roo*_*ian 36 c# structuremap configuration dependency-injection application-settings

如何使用Settings(ApplicationSettingsBase)和依赖注入将所有配置文件代码保留在逻辑代码之外?

配置我指的是客户特定的配置文件.

我是否真的必须每次需要时注入一个配置类,还是有其他模式?

获得一些示例代码会很棒!

样品:

静态配置:

public static class StaticConfiguration
{
    public static bool ShouldApplySpecialLogic { get; set; }
    public static string SupportedFileMask { get; set; }
}

public class ConsumerOfStaticConfiguration
{
    public void Process()
    {
        if (StaticConfiguration.ShouldApplySpecialLogic)
        {
            var strings = StaticConfiguration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

非静态配置:

public interface IConfiguration
{
    bool ShouldApplySpecialLogic { get; set; }
    string SupportedFileMask { get; set; }
}

public class Configuration : IConfiguration
{
    public bool ShouldApplySpecialLogic { get; set; }
    public string SupportedFileMask { get; set; }
}

public class Consumer
{
    private readonly IConfiguration _configuration;

    public Consumer(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void Process()
    {
        if (_configuration.ShouldApplySpecialLogic)
        {
            var strings = _configuration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

具有非静态配置的静态上下文:

public static class Context
{
    public static IConfiguration Configuration { get; set; }
}

public class ConsumerOfStaticContext
{
    public void Process()
    {
        if (Context.Configuration.ShouldApplySpecialLogic)
        {
            var strings = Context.Configuration.SupportedFileMask.Split(',');
            foreach (var @string in strings)
            {

            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Bry*_*tts 29

配置类减少了内容并增加了消费者的耦合.这是因为可能有许多设置与您的类所需的一个或两个无关,但为了实现依赖性,您的实现IConfiguration必须为所有访问器提供值,即使是不相关的访问器.

它还将您的课程与基础知识相结合:"将这些值配置在一起"等详细信息会从应用程序配置中渗透到您的类中,从而增加受不相关系统更改影响的表面区域.

共享配置值的最简单,最灵活的方法是使用构造函数注入值本身,外部化基础结构问题.但是,在对另一个答案的评论中,您表明您害怕拥有大量构造函数参数,这是一个有效的问题.

要认识到的关键点是原始和复杂依赖关系之间没有区别.无论您是依赖于整数还是接口,它们都是您不知道并且必须被告知的事物.从这个角度来看,IConfiguration同样有意义IDependencies.大型构造函数表明,无论参数是原始的还是复杂的,类都有太多的责任.

考虑治疗int,stringbool你一样会和其他任何依赖.它将使您的课程更清晰,更专注,更耐变,更容易进行单元测试.

  • @Rookian:换句话说:在`IConfiguration`类型下对构造函数值进行分组可能会减少构造函数参数的数量,但它不会降低复杂性,这是构造函数膨胀背后的真正危险. (4认同)
  • 我找对了你,你不会使用复杂的类型,但是简单的类型如int,string和bool?如果是这样,如果你有5个不同的配置参数和2个依赖项怎么办?这会使你的构造函数膨胀.对于需要某些配置的每种情况,也许可以使用特定的复杂类型.类似于FileParserConfiguration,BootConfiguration,DatabaseConfiguration.我还不确定我应该用什么:) (3认同)

Mar*_*ann 25

要实现的重要部分是配置只是驱动应用程序行为的几个值源之一.

第二个选项(非静态配置)是最好的,因为它使您能够完全将消费者与配置值的源分离.但是,不需要该接口,因为配置设置通常最好建模为值对象.

如果您仍想从配置文件中读取值,可以从应用程序的Composition Root中执行此操作.使用StructureMap,它可能看起来像这样:

var config = (MyConfigurationSection)ConfigurationManager.GetSection("myConfig");

container.Configure(r => r
    .For<Consumer>()
    .Ctor<MyConfigurationSection>()
    .Is(config));
Run Code Online (Sandbox Code Playgroud)

  • 使用约定.使用StructureMap,入口点是Scan方法. (3认同)