Search code examples
c#.netnull-coalescing-operator

How null-coalsescing operator works


I got three classes (classA, classB and classC) that inherit from an interface 'IFoo'; if use this

var fooItem = (request.classAitem ?? (request.classBitem  as IFoo ?? request.classCitem)) 

or

var fooItem = (request.classAitem ?? request.classBitem ?? request.classCitem as IFoo)

it works just fine but other combinations won't even compile:

var fooItem = (request.classAitem as IFoo ?? request.classBitem ?? request.classCitem)

or

var fooItem = (request.classAitem ?? request.classBitem ?? request.classCitem) as IFoo

It seems to me that in some cases the compiler implicitly unboxes the child classes to their IFoo interface but in some other cases don't. What do you guys think?


Solution

  • In both of your examples that don't work, because ?? is right-associative, we're first trying to determine the data type of this expression:

    request.classBitem ?? request.classCitem
    

    The data type can only be the data type of one of its inputs, if the data types are different. There's obviously no conversions available in either direction here and so you get a compiler error. Note that the compiler will not decide that the data type here is IFoo just because both classes happen to implement it (and if it did, what would happen if they both implemented multiple common interfaces?)

    Compare this to your first two examples. In the first, we first consider this expression:

    request.classBitem  as IFoo ?? request.classCitem
    

    The type of this expression is either IFoo or whatever the data type of request.classCitem is. There's a conversion from the type of request.classCitem to IFoo and so that's obviously selected and so the entire expression's data type is IFoo. That is then used to determine the type of the overall expression (again, IFoo).

    The second case is very similar, since ?? is right associative1, we first have to determine the type of:

    request.classBitem ?? request.classCitem as IFoo
    

    And again, we have a choice between IFoo and whatever the data type of request.classBitem is. There's a conversion to IFoo and so that is chosen.

    1And note, also, that it means the parentheses in the first example are superfluous.