views:

410

answers:

3

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  A: 

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....

Will
+1. Thanks, that worked just fine. I agree that in most cases, just going with the flow would be easier, and that's also what I usually do, but this was a special case...
Mark Seemann
Good to know... I'm actually experimenting with immutable types and xaml serialization. I'm hoping type converters will work for me as well!
Will
+2  A: 

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.

Marc Gravell
I would agree in most cases, and that's also what I usually do, but this was a special case.
Mark Seemann
A: 

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.

Dejan
In normal cases I agree with you entirely, and that is also my normal approach, but this was a special case. I just made it work with TypeConverts as suggested by Will, and that worked just fine, so your initial claim is not true.
Mark Seemann