Search code examples
c#type-conversionresharpernullableresharper-2016

C# is operator with nullable types always false according to ReSharper


I'm attempting to convert an object to a bool type and want to convert bool and Nullable<bool> types. I also want to make sure I make the appropriate casts where possible. So I have the following code:

if (value is bool)
{
    boolValue = (bool) value;
}
else if (value is bool? && ((bool?)value).HasValue)
{
    boolValue = ((bool?) value).Value;
}
else
{
    throw new ArgumentException("Value must be a boolean type");
}

ReSharper 2016 informs me that value is bool? will always evaluate to false in this stack of if statements. Why is that? That would imply that Nullable<bool> doesn't inherit from object (impossible) or that value is bool will capture a bool?.

It's also possible that ReSharper 2016 has a bug; I see that the implementation of System.Windows.Controls.BooleanToVisibilityConverter.Convert is pretty much identical. I doubt that WPF core would have such a mistake in it, leading me to believe it's an issue with ReSharper.


Solution

  • When a value type is stored as object it is boxed. Boxing of Nullable<T> gets special treatment:

    Objects based on nullable types are only boxed if the object is non-null. If HasValue is false, the object reference is assigned to null instead of boxing ... Boxing a non-null nullable value type boxes the value type itself, not the System.Nullable that wraps the value type.

    And, per the documentation for is:

    An is expression evaluates to true if the provided expression is non-null, and the provided object can be cast to the provided type without causing an exception to be thrown.

    So, using both of these you can deduce (see fiddle) that in the null case:

    bool? x = null;
    object obj = x;   // assigns obj = null
    obj is bool?      // false, obj is null
    obj is bool       // false, obj is null
    

    And in the non-null case:

    bool? x = true;
    object obj =  x;  // obj is boxed bool (true)
    obj is bool?      // true, obj unboxes to bool?
    obj is bool       // true, obj unboxes to bool
    

    So ReSharper is correct: your first branch will evaluate as true if value is true or false (whether the object was assigned from a bool or bool? is not relevant or even known). The second branch will always be false in this case.