TypeConverter не может конвертировать из некоторых базовых типов в те же базовые типы

Почему те возвращают true:

  TypeDescriptor.GetConverter(typeof(double)).CanConvertTo(typeof(double));
  TypeDescriptor.GetConverter(typeof(int)).CanConvertTo(typeof(int));

когда те возвращают false?

  TypeDescriptor.GetConverter(typeof(decimal)).CanConvertTo(typeof(decimal));
  TypeDescriptor.GetConverter(typeof(bool)).CanConvertTo(typeof(bool));

Событие, считающее, что все конвертеры, возвращаемые GetConverter, должны только преобразовывать типы в строку и из нее:

Я использую .NET Framework 4.5.2.

Ответ 1

DecimalConverter (а также DoubleConverter и Int32Converter) переопределяет CanConvertTo, чтобы указать, что он может преобразовать в строки (из-за того, что делает base.CanConvertTo), и всех примитивных типов CLR. Из Справочный источник:

public override bool CanConvertTo(ITypeDescriptorContext context, Type t) 
{
    if (base.CanConvertTo(context, t) || t.IsPrimitive) {
        return true;
    }
    return false;
}

decimal НЕ является примитивным типом с точки зрения CLR, поэтому преобразователь возвращает false при передаче typeof(decimal).

BooleanConverter не переопределяет CanConvertTo, поэтому он попадает в базовую реализацию, которая допускает только преобразование в string:

public virtual bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
{
    return (destinationType == typeof(string));
}

Если вы спрашиваете, почему он был разработан таким образом, то могут сказать только дизайнеры Framework, но я подозреваю это, потому что это тривиальная проверка, чтобы проверить, пытаетесь ли вы конвертировать из одного типа в один и тот же тип.

Учитывая, что их целью является преобразование нестроковых типов в/из строк для отображения в сетках свойств, XAML и т.д., неудивительно, что он не поддерживает полностью нестрочные преобразования.

Ответ 2

Boolean, Char, DateTime, String и Object TypeConverter наследуют от BaseTypeConverter и не перезаписывают CanConvertTo, которые возвращают true, только если переданный тип имеет строку типа. Вот почему TypeDescriptor.GetConverter(typeof(bool)).CanConvertTo(typeof(bool)) является ложным.

Преобразователи типов для байтов, двоичных, Int16, Int32, Int64, SByte, Single, UInt16, UInt32 и UInt64 все получены из BaseNumberConverter, который возвращает true для CanCovertTo для типов, которые являются строками или примитивными типами.

Десятичный наследует и от BaseNumberConverter, но поскольку он не является примитивным, он передает тип decimail в CanConvertTo, что приведет к ложному. Вот почему TypeDescriptor.GetConverter(typeof(decimal)).CanConvertTo(typeof(decimal)) является ложным.

Здесь полная диаграмма для результатов CanConvertTo

FROM/TO     Bol Byt Chr DTm Dec Dbl I16 I32 I64 SBt Sng Str Obj U16 U32 U64
Boolean                                                 +               
Byte        +   +   +           +   +   +   +   +   +   +       +   +   +
Char                                                    +               
DateTime                                                +               
Decimal     +   +   +           +   +   +   +   +   +   +       +   +   +
Double      +   +   +           +   +   +   +   +   +   +       +   +   +
Int16       +   +   +           +   +   +   +   +   +   +       +   +   +
Int32       +   +   +           +   +   +   +   +   +   +       +   +   +
Int64       +   +   +           +   +   +   +   +   +   +       +   +   +
SByte       +   +   +           +   +   +   +   +   +   +       +   +   +
Single      +   +   +           +   +   +   +   +   +   +       +   +   +
String                                                  +               
Object                                                  +               
UInt16      +   +   +           +   +   +   +   +   +   +       +   +   +
UInt32      +   +   +           +   +   +   +   +   +   +       +   +   +
UInt64      +   +   +           +   +   +   +   +   +   +       +   +   +

Типы и их преобразователи

Type        Converter class     Converter inherits from
----------  ------------------  -----------------------
Boolean     BooleanConverter    TypeConverter
Byte        ByteConverter       BaseNumberConverter
Char        CharConverter       TypeConverter
DateTime    DateTimeConverter   TypeConverter
Decimal     DecimalConverter    BaseNumberConverter
Double      DoubleConverter     BaseNumberConverter
Int16       Int16Converter      BaseNumberConverter
Int32       Int32Converter      BaseNumberConverter
Int64       Int64Converter      BaseNumberConverter
SByte       SByteConverter      BaseNumberConverter
Single      SingleConverter     BaseNumberConverter
String      StringConverter     TypeConverter
Object      TypeConverter       Object
UInt16      UInt16Converter     BaseNumberConverter
UInt32      UInt32Converter     BaseNumberConverter
UInt64      UInt64Converter     BaseNumberConverter
UInt32      UInt32Converter     BaseNumberConverter
UInt64      UInt64Converter     BaseNumberConverter