I am working on an IValueConverter
implementation which would convert bool?
values. For the sake of versatility I've decided to use TypeConverter
to convert input value to bool?
. Since its main purpose is to be used as a converter for XAML bindings I'd like to avoid having exceptions thrown as it results in significant decrease of UI performance. To do that I tried using TypeConverter.IsValid
method, but came across peculiar behavior, an example of which is shown in the following code:
//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);
Perhaps I'm wrong, but I'd expect the IsValid
method to return false
whenever a value cannot be converted and true
otherwise, but clearly that's not the case with an empty string and NullableConverter
(same behavior can be observed for other nullable types).
Is this a bug or rather a design choice? And if the latter, are there any other similar cases?
EDIT
After inspecting the source code for NullableConverter
I think I've found the reason for this behavior. Here's the IsValid
implementation:
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);
}
In my case the simpleTypeConverter
is of type BooleanConverter
and, understandably, it returns false
for string.Empty
. On the other hand, here's the ConvertFrom
implementation:
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);
}
}
Obviously, string.Empty
falls into the second if
statement, hence the null
result without an exception.
Knowing the reason for this behavior the question still remains - is it an oversight, or is it intended to work this way? I've submitted a bug report and will post any conclusions to come out of it.
What different people expect in some of these situations probably isn't the same, but to me the behavior given by the framework in this case seems reasonable.
For example: in the following cases, the behavior seems perfectly reasonable to me.
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
From @C.Evenhuis' comment, this is the behavior that I believe was deemed questionable.
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
is doing something which I find very good. If you'll note, var isNullAString = null is string
returns false
! It makes more sense to me for null to be converted into an empty string, even if that's not what you were expecting.
As to the last unaddressed part in your question..
Perhaps I'm wrong, but I'd expect the IsValid method to return false whenever a value cannot be converted and true otherwise, but clearly that's not the case with an empty string and NullableConverter (same behavior can be observed for other nullable types).
I believe this was satisfactorily answered in a comment above, which stated
The IsValid method is used to validate a value within the type rather than to determine if value can be converted to the given type. For example, IsValid can be used to determine if a given value is valid for an enumeration type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With