【问题标题】:Immutable types as configuration properties不可变类型作为配置属性
【发布时间】:2010-11-29 11:05:47
【问题描述】:

是否可以通过 .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'类型的属性'criterion'的字符串转换的转换器。

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

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

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

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

【问题讨论】:

    标签: c# .net configuration serialization


    【解决方案1】:

    您也许可以使用一些 TypeConverters 来帮助该过程(链接到 System.Configurations.ConfigurationConverter)。

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

    【讨论】:

    • +1。谢谢,效果很好。我同意在大多数情况下,顺其自然会更容易,这也是我通常所做的,但这是一个特例......
    • 很高兴知道...我实际上正在试验不可变类型和 xaml 序列化。我希望类型转换器也对我有用!
    【解决方案2】:

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

    【讨论】:

    • 在大多数情况下我会同意,这也是我通常做的,但这是一个特例。
    【解决方案3】:

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

    最简单的解决方案是在配置和应用程序之间放置另一个抽象级别。您可以应用配置提供者模式,并将配置部分的“对所有人免费”可变类转换为不可变类,然后由您的应用程序使用。

    我必须说这就是配置部分的使用方式。我知道有一个 wright back 选项,但我以前从未使用过它。

    代码可能如下所示:

    配置处理程序

    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);
        }
      }
    }
    

    我就是这样做的,到目前为止它对我很有帮助。

    希望对你有帮助。

    【讨论】:

    • 在正常情况下我完全同意你的看法,这也是我的正常做法,但这是一个特例。我刚刚按照 Will 的建议让它与 TypeConverts 一起工作,而且效果很好,所以你最初的说法是不正确的。
    【解决方案4】:

    您可以通过像这样设置属性值来抑制错误:

    public string SomeProperty { get; set; } = null!/*This property will always be populated*/;
    

    这样,您的其余代码将值视为不可为空。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-11
      • 1970-01-01
      • 2020-05-28
      • 2011-02-02
      • 2019-06-04
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多