Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistency in TypeConverter behavior?

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.

like image 790
Grx70 Avatar asked May 23 '15 20:05

Grx70


1 Answers

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.

like image 117
Frank Bryce Avatar answered Sep 23 '22 17:09

Frank Bryce