不可变类型作为配置属性

时间:2009-09-18 11:33:58

标签: c# .net configuration serialization

是否可以将不可变类型用作.NET配置API的配置属性?

假设我有一个名为MyClass的不可变类型:

public class ImmutableClass
{
    private readonly int value;

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

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

我想在ConfigurationSection中使用此类型作为配置属性:

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

当我这样做时,我无法序列化和反序列化MyConfigurationSection,因为它会抛出此异常:

  

System.Configuration.ConfigurationErrorsException:属性“criterion”的值无法转换为字符串。错误是:无法找到支持转换为/来自字符串的转换器,用于“FindCriterion”类型的属性“标准”。

如果我从ConfigurationElement派生出Im​​mutableClass,当我尝试序列化和反序列化配置部分时会出现此异常:

  

System.Reflection.TargetInvocationException:调用目标抛出了异常。 ---> System.Reflection.TargetInvocationException:调用目标抛出了异常。 ---> System.MissingMethodException:没有为此对象定义无参数构造函数。

我可以完全控制ImmutableClass,因此我可以实现所需的任何接口。

有什么办法可以挂钩配置API,以便可以这种方式使用ImmutableClass吗?

3 个答案:

答案 0 :(得分:4)

就我个人而言,我认为您最好将配置部分中的数据(看似需要变量)分开,以及如何在对象模型中表示它。没有什么可以阻止你有两个表示 - 一个简单的(DTO / POCO)版本的配置,你的自定义版本(在这种情况下是不可变的)在你的应用程序中实际使用。

答案 1 :(得分:1)

您可以使用一些TypeConverters来帮助完成此过程(链接到System.Configurations.ConfigurationConverter)。

真正的问题是你为什么要给自己造成这么多麻烦?有时候,最好放下并接受它而不是打架。如果您尝试以除了针对您的特定方式之外的任何方式执行此操作,框架的某些部分会令人沮丧....

答案 2 :(得分:0)

我会放弃那个诅咒,因为这个想法被诅咒失败了。所有配置节处理程序必须具有默认(无参数)构造函数。您的不可变对象不是这种情况。

最简单的解决方案是在配置和应用程序之间添加另一个抽象级别。您可以应用配置提供程序模式,并将配置节的“free for all”可变类转换为可由应用程序使用的不可变类。

我必须说这是应该如何使用配置部分。我知道有一个可靠的选项,但我以前从未使用过它。

代码可能如下所示:

配置处理程序

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

从XML文件中获取配置值并进入对象后,使用配置提供程序模式来使用应用程序中的配置。

配置提供程序看起来像这样:

public MyConfigurationProvider : IMyconfigurationProvider
{

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

我就是这样做的,到目前为止它已经为我服务了。

希望它有所帮助。