Несоответствие поведения TypeConverter?
Я работаю над реализацией IValueConverter
, которая преобразует значения bool?
. Ради универсальности я решил использовать TypeConverter
для преобразования входного значения в bool?
. Поскольку его основная цель заключается в использовании конвертера для привязок XAML, я бы хотел избежать исключения, поскольку это привело к значительному снижению производительности пользовательского интерфейса. Для этого я попытался использовать метод 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
(такое же поведение наблюдается и для других типов с нулевым значением).
Это ошибка или, скорее, выбор дизайна? И если последнее, есть ли другие подобные случаи?
ИЗМЕНИТЬ
После проверки исходного кода для 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);
}
В моем случае simpleTypeConverter
имеет тип BooleanConverter
и, по понятным причинам, он возвращает false
для string.Empty
. С другой стороны, здесь реализация 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
не содержит исключения.
Зная причину такого поведения, вопрос все еще остается - это надзор, или он намерен работать таким образом? Я отправил отчет об ошибке и опубликую любые выводы, чтобы выйти из него.
Ответы
Ответ 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 всякий раз, когда значение не может быть преобразовано и истинно в противном случае, но ясно, что не случай с пустой строкой и NullableConverter (такое же поведение наблюдается для других типы с нулевым значением).
Я считаю, что это было удовлетворительно сказано в комментарии выше, в котором говорилось
Метод IsValid используется для проверки значения внутри типа, а не для определения того, может ли значение быть преобразовано в заданный тип. Например, IsValid может использоваться для определения того, действительно ли заданное значение допустимо для типа перечисления.
Ответ 2
Причина, по которой у вас возникла проблема, заключается в том, что String.Empty является классом vs "" является литералом. Это ReadOnly Varialble. что означает, что это NULL Переменная типа string.