Что такое неявный контракт для типа свойства при использовании с атрибутом ConfigurationProperty? - PullRequest
4 голосов
/ 19 февраля 2011

В качестве примера я хотел бы сериализовать и десериализовать объект 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' не может быть преобразовано в строку. Ошибка: Невозможно найти конвертер, который поддерживает преобразование в / из строки для свойства 'ver' типа 'Версия'.

System.Version.ToString() записывает объект в общеизвестный строковый формат, который может использоваться System.Version.ctor(string), поэтому для этого типа вполне возможно существование "преобразователя". Для сравнения, тип System.TimeSpan имеет аналогичные методы и функции (Parse вместо .ctor(string)), и этот тип хорошо работает с системой конфигурации (конвертер уже должен существовать).

Как узнать, есть ли у типа подходящий конвертер? Какому договору (неявному или иному) должен удовлетворять такой тип?

1 Ответ

4 голосов
/ 16 августа 2012

Для работы 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);
    }
}
...