当使用ConfigurationProperty属性时,一个属性的类型隐含的契约是什么?

4
作为一个例子,我想序列化和反序列化一个 System.Version 对象作为我的应用程序自定义配置部分的一部分。我尝试使用以下属性声明来实现:
public class ConfigElement : ConfigurationElement
{
    [ConfigurationProperty("ver", IsRequired = false, DefaultValue = "1.2.4.8")]
    public Version Ver
    {
        get { return (Version)this["ver"]; }
        set { this["ver"] = value; }
    }
}

很不幸,尝试序列化或使用此属性(带有或不带有DefaultValue)将导致以下异常信息。

System.Configuration.ConfigurationErrorsException:属性“ver”的值无法转换为字符串。错误是:找不到支持类型为“Version”的属性“ver”的字符串转换器。

System.Version.ToString() 将对象写入一个众所周知的字符串格式,该格式可被 System.Version.ctor(string) 使用,因此似乎有可能存在适用于此类型的“转换器”。相比之下,System.TimeSpan 类型具有类似的方法和函数(在.ctor(string)处使用Parse),并且该类型与配置系统配合良好(转换器必须已经存在)。

我如何知道某个类型是否具有适当的转换器?这种类型必须满足什么契约(隐式或明示)?


一种方法是尝试反序列化并查看是否会出现此异常。 - John Saunders
Version类不支持XML序列化,它的所有属性都是只读的。请自己创建一个。 - Hans Passant
1个回答

4
为了让ConfigurationProperty起作用,所使用的类型必须与 TypeConverter相关联,以便知道如何从字符串转换。 ConfigurationProperty确实具有 Converter属性,但遗憾的是它是只读的。更糟糕的是,Version没有声明隐式TypeConverter。不过,您可以通过在程序中以编程方式添加 TypeConverterAttribute到Version类来解决所有这些问题。因此,在访问配置之前,您需要基本上调用此行一次。
TypeDescriptor.AddAttributes(typeof(Version), new TypeConverterAttribute(typeof(VersionTypeConverter)));
// ... you can call configuration code now...

使用以下定制的 VersionTypeConverter:
public class VersionTypeConverter : TypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        return new Version((string)value);
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
            return true;

        return base.CanConvertFrom(context, sourceType);
    }
}

干得好,先生!太遗憾了,我们不能通过应用程序配置或某些事件来注册这些类型。虽然前者不太难启用。 - Steve Guidi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接