C# 类型转换器行为不一致?

C# 类型转换器行为不一致?,c#,typeconverter,C#,Typeconverter,我正在研究一个IValueConverter实现,它将转换bool?值。为了通用性,我决定使用TypeConverter将输入值转换为bool?。由于它的主要用途是用作XAML绑定的转换器,我希望避免抛出异常,因为它会导致UI性能的显著降低。为此,我尝试使用TypeConverter.IsValid方法,但遇到了特殊的行为,下面的代码中显示了一个例子: //returned converter is a NullableConverter var converter = TypeDescript

我正在研究一个
IValueConverter
实现,它将转换
bool?
值。为了通用性,我决定使用
TypeConverter
将输入值转换为
bool?
。由于它的主要用途是用作XAML绑定的转换器,我希望避免抛出异常,因为它会导致UI性能的显著降低。为此,我尝试使用
TypeConverter.IsValid
方法,但遇到了特殊的行为,下面的代码中显示了一个例子:

//returned converter is a NullableConverter
var converter = TypeDescriptor.GetConverter(typeof(bool?));

//this method returns false
converter.IsValid(string.Empty);

//yet this method returns null without throwing an exception
converter.ConvertFrom(string.Empty);
也许我错了,但我希望
IsValid
方法在值无法转换时返回
false
,否则返回
true
,但对于空字符串和
NullableConverter
(对于其他可空类型也可以观察到相同的行为)

这是一个bug还是一个设计选择?如果是后者,还有其他类似的情况吗

编辑

在检查了for
NullableConverter
之后,我想我已经找到了这种行为的原因。以下是
IsValid
实现:

public override bool IsValid(ITypeDescriptorContext context, object value) {
    if (simpleTypeConverter != null) {
        object unwrappedValue = value;
        if (unwrappedValue == null) {
            return true; // null is valid for nullable.
        }
        else {
            return simpleTypeConverter.IsValid(context, unwrappedValue);
        }
    }

    return base.IsValid(context, value);
}        
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
    if (value == null || value.GetType() == this.simpleType) {
        return value;
    }
    else if (value is String && String.IsNullOrEmpty(value as String)) {
        return null;
    }
    else if (this.simpleTypeConverter != null) {
        object convertedValue = this.simpleTypeConverter.ConvertFrom(context, culture, value);
        return convertedValue;
    }
    else {
        return base.ConvertFrom(context, culture, value);
    }
}
在我的例子中,
simpleTypeConverter
属于
BooleanConverter
类型,可以理解,它为
string.Empty返回
false
。另一方面,下面是来自
实现的
转换:

public override bool IsValid(ITypeDescriptorContext context, object value) {
    if (simpleTypeConverter != null) {
        object unwrappedValue = value;
        if (unwrappedValue == null) {
            return true; // null is valid for nullable.
        }
        else {
            return simpleTypeConverter.IsValid(context, unwrappedValue);
        }
    }

    return base.IsValid(context, value);
}        
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
    if (value == null || value.GetType() == this.simpleType) {
        return value;
    }
    else if (value is String && String.IsNullOrEmpty(value as String)) {
        return null;
    }
    else if (this.simpleTypeConverter != null) {
        object convertedValue = this.simpleTypeConverter.ConvertFrom(context, culture, value);
        return convertedValue;
    }
    else {
        return base.ConvertFrom(context, culture, value);
    }
}
显然,
string.Empty
属于第二个
if
语句,因此
null
结果没有异常


知道这种行为的原因,问题仍然存在——这是一种疏忽,还是有意这样做?我已经提交了一份报告,并将发表任何结论。

不同的人在某些情况下的期望可能不一样,但对我来说,框架在这种情况下给出的行为似乎是合理的

例如:在以下情况下,我认为这种行为是完全合理的

var converter = TypeDescriptor.GetConverter(typeof(bool?));

bool? nullableBool1 = converter.ConvertFrom(string.Empty); // returns null
bool? nullableBool2 = converter.ConvertFrom("true"); // returns true
bool? nullableBool3 = converter.ConvertFrom("false"); // returns false

bool? nullableBool4 = converter.ConvertFromString(string.Empty); // returns null
bool? nullableBool5 = converter.ConvertFromString("true"); // returns true
bool? nullableBool6 = converter.ConvertFromString("false"); // returns false
从@C.Evenhuis的评论来看,我认为这种行为是值得怀疑的

var converter = TypeDescriptor.GetConverter(typeof(bool?));
var string1 = converter.ConvertToString(null); // returns ""
var string2 = converter.ConvertToString(true); // returns "true"
var string3 = converter.ConvertToString(false); // returns "false"
ConvertToString
正在做一些我觉得很好的事情。请注意,
var isNullAString=null是string
返回
false
!对我来说,将null转换为空字符串更有意义,即使这不是您所期望的

至于你问题中最后一个未解决的部分

也许我错了,但我希望IsValid方法在无法转换值时返回false,否则返回true,但对于空字符串和NullableConverter,情况显然不是这样(对于其他nullable类型,可以观察到相同的行为)

我相信这在上面的评论中得到了令人满意的回答

IsValid方法用于验证类型中的值,而不是确定值是否可以转换为给定类型。例如,IsValid可用于确定给定值是否对枚举类型有效


出现此问题的原因是String.Empty是一个类,而“”是一个文本。它是一个只读变量。这意味着它是一个字符串类型的空变量。

当我尝试您的示例时,
IsValid
抛出一个
FormatException
,消息
字符串未被识别为有效的布尔值。
但是,文档中说从.NET Framework 4开始,IsValid方法捕获CanConvertFrom和ConvertFrom方法的异常。如果输入值类型导致CanConvertFrom返回false,或者输入值导致ConvertFrom引发异常,IsValid方法将返回false
返回一个空字符串。我猜
null
对于
null
无效?@MariusBancila我刚刚测试了从2.0到4.5.1的代码目标框架版本,在任何情况下,
ConvertFrom
IsValid
都不会引发异常。不过有趣的是,直到并包括版本3.5
IsValid
返回
true
…是否有可能
ConvertFrom
会“吞咽”异常?根据文档,它应该吞咽从.NET 4.0开始的异常。但是我在.NET 4.5项目中进行了测试。因此我没有得到它。这不是一个bug。根据TypeConverter.IsValid的MSDN描述:IsValid方法用于验证类型中的值,而不是确定值是否可以转换为给定类型。例如,IsValid可用于确定给定值是否对枚举类型有效。”