类型转换器无法从某些基本类型转换为相同的基本类型

本文关键字:类型 类型转换 转换器 | 更新日期: 2023-09-27 17:56:29

为什么那些返回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 返回的所有转换器应该只将类型与字符串相互转换的事件:

  • 双转换器
  • Int32转换器
  • 十进制转换器
  • 布尔转换器

我正在使用.NET Framework 4.5.2。

类型转换器无法从某些基本类型转换为相同的基本类型

BooleanCharDateTimeStringObjectTypeConverter继承自BaseTypeConverter并且不覆盖CanConvertTo,只有当传递的类型是类型string时才返回true。 这就是为什么TypeDescriptor.GetConverter(typeof(bool)).CanConvertTo(typeof(bool))是错误的。

ByteDoubleInt16Int32Int64SByteSingleUInt16UInt32UInt64 的类型转换器都BaseNumberConverter派生自字符串或基元类型的CanCovertTo返回 true。

Decimal也继承自BaseNumberConverter,但由于它不是基元,因此将十进制类型传递给CanConvertTo将导致 false。 这就是为什么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
DecimalConverter

以及DoubleConverterInt32Converter)覆盖CanConvertTo,以指示它可以转换为字符串(因为这就是base.CanConvertTo的作用)和所有CLR基元类型。 从参考来源:

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

从 CLR 的角度来看,decimal 不是基元类型,因此转换器在传递typeof(decimal)时返回false

BooleanConverter 不会覆盖CanConvertTo,因此它落在仅允许转换为 string 的基本实现中:

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

如果你问为什么它是这样设计的,那么只有框架设计师可以说,但我怀疑这是因为这是一个微不足道的检查,看看你是否试图从一种类型转换为相同的类型。

考虑到它们的目的是将非字符串类型转换为字符串/从字符串转换为在属性网格、XAML 等中显示的字符串,因此它不完全支持非字符串转换也就不足为奇了。