Immutable types as configuration properties

2019-06-19 01:27发布

问题:

Is it possible to use immutable types as configuration properties with .NET's configuration API?

Let's say I have an immutable type called MyClass:

public class ImmutableClass
{
    private readonly int value;

    public ImmutableClass(int value)
    {
        this.value = value;
    }

    public int Value
    {
        get { return this.value; }
    }
}

I would like to use this type as a configuration property in a ConfigurationSection:

public class MyConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty("foo")]
    public ImmutableClass Foo
    {
        get { return (ImmutableClass)base["foo"]; }
        set { base["foo"] = value; }
    }
}

When I do this, I can't serialize and deserialize MyConfigurationSection because it throws this exception:

System.Configuration.ConfigurationErrorsException: The value of the property 'criterion' cannot be converted to string. The error is: Unable to find a converter that supports conversion to/from string for the property 'criterion' of type 'FindCriterion'.

If I derive ImmutableClass from ConfigurationElement, I get this exception when I try to serialize and deserialize the configuration section:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMethodException: No parameterless constructor defined for this object.

I have full control over ImmutableClass, so I can implement whichever interface is needed.

Is there any way I can hook into the configuration API so that ImmutableClass can be used in this way?

回答1:

You might be able to use some TypeConverters to help the process along (link to System.Configurations.ConfigurationConverter).

The real question is why do you want to cause yourself so much trouble? There are just some times where its better to lay back and take it than put up a fight. Some parts of the framework are frustrating if you try to do it any way other than the specific one laid out for you....



回答2:

Personally I think you would do better to separate out the data in the configuration section (which seemingly needs to be mutable), and how you represent it in your object model. There is nothing stopping you having two representations - a simple (DTO/POCO) version for config, and your custom version (immutable in this case) for real usage in your app.



回答3:

I would abandon that curse because the idea is cursed to fail. All configuration section handlers must have a default (parameterless) constructor. This is not the case with your immutable object.

The simplest solution is to put another abstraction level in between the configuration and your application. You could apply the configuration provider pattern and that would convert the "free for all" mutable classes of the configuration section into immutable classes that would then be consumed by your application.

I must say that this is how the configuration sections should be used. I know that there is a wright back option but I have never used it before.

The code could look something like the following:

The configuration handler

public class SectionHandler : ConfigurationSection
{
  [ConfigurationProperty("foo")]
  public MyObject ConfigurationValue
  {
    get { return (MyObject) this["foo"]; }
  }
}

After you have gotten the configuration value out of the XML file and into a object use the configuration provider pattern to consume the configuration in your application.

The configuration provider would could look something like this:

public MyConfigurationProvider : IMyconfigurationProvider
{

  public MyImmutabble ConfigurationValue
  {
    get
    {
      var configurationvalue = (MyObject) ConfigurationManager.GetSection("mySection");
      return new MyImmutable(configurationvalue.ConfigurationValue);
    }
  }
}

This is how I do it and it has served me so far.

Hope it helps.