TypeConverter无法将一些基本类型转换为相同的基本类型。

15

为什么这些会返回 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
我不确定除了BCL团队的成员之外,是否有人真正能解释这是否是一个实际原因,还是只是一个疏忽。我确实在BaseNumberConverter.CanConvertTo中看到了逻辑,它检查了基本类型,而Decimal则不是,从而解释了与Decimal的差异。但为什么不支持Decimal呢? - Michael Liu
2个回答

8

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

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

Decimal也继承自BaseNumberConverter,但由于它不是基本类型,将decimal类型传递给CanConvertTo将导致返回false。这就是为什么TypeDescriptor.GetConverter(typeof(decimal)).CanConvertTo(typeof(decimal))为false的原因。

下面是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

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

decimal 不是 CLR 视角下的基元类型,因此当传递 typeof(decimal) 时,转换器会返回 false

BooleanConverter 没有覆盖 CanConvertTo,因此它会落到基本实现上,只允许转换为 string

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

如果你在问为什么它被设计成这样,只有框架的设计者才能回答,但我猜测这是因为检查是否试图将一个类型转换为相同类型是一个微不足道的检查。
考虑到它们的目的是将非字符串类型转换为字符串以便在属性网格、XAML等中显示,所以它不完全支持非字符串转换并不令人意外。

1
bool不是一个原始类型吗?https://msdn.microsoft.com/zh-cn/library/system.type.isprimitive.aspx - Matthieu
我刚刚通过反射检查了一下,typeof(bool).IsPrimitive为true,所以我不知道“从CLR的角度来看,bool不是原始类型”是什么意思。 - Daniel Gimenez
@DanielGimenez 我错了。有趣的是,这意味着 DecimalConverter.CanConvertTo(typeof(bool)) 返回 true,这毫无意义。它似乎将 0 转换为 false,而将其他任何东西转换为 true,就像 C++ 一样。 - D Stanley
我只是觉得在@Matthieu之前没有人想到过这个问题。为什么你可以将数字转换为布尔值,但不能将布尔值转换为数字,这似乎是一个疏忽。 - Daniel Gimenez
@DanielGimenez 我怀疑将数字转换为布尔值并不是最初的设计目的 - 目的是能够将值转换为字符串(以在属性框中显示和嵌入标记)并从字符串解析(当在属性网格或标记中更改设置时)。此外,由于它是不可逆的(如何将 true 转换为 4?),因此不允许这样做是有道理的。 - D Stanley

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