简体   繁体   中英

What is the implicit contract for a property's type when used with the ConfigurationProperty attribute?

As an example, I would like to serialize and deserialize a System.Version object as part of my application's custom configuration section. I am attempting to do so with the following property declaration:

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

Unfortunately, attempting to serialize or use this property (with or without the DefaultValue ) yields the following exception message.

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

System.Version.ToString() writes the object to a well-known string format which is consumable by System.Version.ctor(string) , so it seems feasible for a "converter" to exist for this type. Comparably, the System.TimeSpan type has similar methods and functions ( Parse in-place of .ctor(string) ) and the type works well with the configuration system (a converter must already exist).

How do I know if a type has a suitable converter? What contract (implicit or otherwise) must such a type satisfy?

For the ConfigurationProperty to work, the type used must be associated with a TypeConverter than knows how to convert from a string. ConfigurationProperty does have a Converter property, but alas, it's read-only. And, that's really bad luck, Version does not have an implicit TypeConverter declared either.

What you can do though, is add a TypeConverterAttribute to the Version class programmatically, and it will work around all these issues. So you need to basically call this line once in your program before accessing the configuration:

TypeDescriptor.AddAttributes(typeof(Version), new TypeConverterAttribute(typeof(VersionTypeConverter)));
// ... you can call configuration code now...

with the following custom-made 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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM