3

I am developing an application containing a class which loads application settings from a configuration file.

Settings class:

public sealed class MyAppSettings : IMyAppSettings
{
    private IMyAppSettings DefaultSettingsInstance;

    public MyAppSettings()
    {
        DefaultLanguage = "en";

        var config = ConfigurationManager.GetSection("MyAppSettings") as NameValueCollection;

        if (config != null)
        {
            if (!string.IsNullOrEmpty(config["DefaultLanguage"]))
                DefaultLanguage = config["DefaultLanguage"];
        }
    }

    public static IMyAppSettings Default
    {
        get
        {
            return DefaultSettingsInstance ?? (DefaultSettingsInstance = new MyAppSettings());
        }
        set
        {
            if (value == null)
                throw new ArgumentNullException("value");

            DefaultSettingsInstance = value;
        }
    }

    public string DefaultLanguage { get; private set; }

}

Class which is using setting (version 1):

public sealed class SomeClass
{
    public SomeFunction()
    {
        // Using language setting here
        if(MyAppSettings.Default.DefaultLanguage == "en")
        {
            ...
        }
    }
}

or version 2:

public sealed class SomeClass
{
    private readonly string _defaultLanguage;

    public SomeClass(string defaultLanguage)
    {
        if(string.IsNullOrEmpty(defaultLanguage))
            throw new ArgumentNullException("defaultLanguage");

        _defaultLanguage = defaultLanguage;
    }

    public SomeFunction()
    {
        // Using language setting here
        if(_defaultLanguage == "en")
        {
            ...
        }
    }
}

Both classes and interface are located in the same assembly.

What approach is better for a global application settings, pass it via construction injection or use an ambient context or something else?

4

In your Version 2, the requirement of a default language is explicit, which I think is a good thing.

In Version 1, if you don't look at the source code it will be not obvious where it takes the default language from, and appear like "magic", which is not a good thing.

There's definitely no one-size-fits-all solution for choosing between constructor injection / setter injection / ambient context, but in this particular example I think you'll have a cleaner API and more robust code with constructor injection.

2

In version 1 it looks like you're using a static reference to look up the setting, which is generally more cumbersome to control in unit-testing (you're writing tests, right?) than a constructor-injected value, as in version 2.

Also with version 2, as Janos says in his answer, the explicit requirement of a default language is a good thing, because consumers will be aware of it at the time code is written, rather than possibly missing it at runtime.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.