【问题标题】:Inconsistency in TypeConverter behavior?TypeConverter 行为不一致?
【发布时间】:2015-08-05 16:55:04
【问题描述】:

我正在开发一个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 的情况(对于其他可为空的类型也可以观察到相同的行为)。

这是一个错误还是一个设计选择?如果是后者,是否还有其他类似的案例?

编辑

在检查了source codeNullableConverter 之后,我想我已经找到了这种行为的原因。这是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);
}        

在我的例子中,simpleTypeConverterBooleanConverter 类型,可以理解的是,它为 string.Empty 返回 false。另一方面,这是ConvertFrom 的实现:

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 结果无一例外。

知道这种行为的原因后,问题仍然存在 - 是疏忽,还是打算以这种方式工作?我已经提交了bug report,并将发布任何结论。

【问题讨论】:

  • 当我尝试您的示例时,IsValid 会抛出带有消息 String was not recognized as a valid Boolean.FormatException 但是,文档说“从 .NET Framework 4 开始,IsValid 方法从 CanConvertFrom 和 ConvertFrom 捕获异常方法。如果输入值类型导致 CanConvertFrom 返回 false,或者如果输入值导致 ConvertFrom 引发异常,则 IsValid 方法返回 false。"
  • myNullableConverter.ConvertToString(null) 返回一个空字符串也很有趣。我猜nullNullable<T> 无效?
  • @MariusBancila 我刚刚测试了从 2.0 到 4.5.1 的代码定位框架版本,在任何情况下,ConvertFromIsValid 都没有抛出异常。有趣的是,直到并包括版本 3.5 IsValid 返回 true... ConvertFrom 是否有可能“吞下”异常?
  • 根据文档,它应该从 .NET 4.0 开始吞下异常。但我在 .NET 4.5 项目中进行了测试。所以我不明白。
  • 这不是错误。来自 TypeConverter.IsValid 的 MSDN 描述:“IsValid 方法用于验证类型内的值而不是确定值是否可以转换为给定类型。例如,可以使用 IsValid确定给定值是否对枚举类型有效。"

标签: c# typeconverter


【解决方案1】:

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

例如:在以下情况下,我的行为似乎完全合理。

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 is string 返回false!将 null 转换为空字符串对我来说更有意义,即使这不是您所期望的。

关于您问题中最后一个未解决的部分..

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

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

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

【讨论】:

    【解决方案2】:

    您遇到问题的原因是因为 String.Empty 是一个类,而 "" 是一个字面量。它是一个只读变量。这意味着它是一个字符串类型的 NULL 变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-21
      • 2013-12-17
      • 2018-08-27
      • 2016-01-13
      • 1970-01-01
      • 2019-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多