Yes it does. As ever, the C# language specification is the definitive source1.
From the C# 3 spec, section 7.12 (v3 rather than 4, as the v4 spec goes into dynamic details which aren't really relevant here):
The type of the expression a ?? b
depends on which implicit conversions are available between the types of the operands. In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a, B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise. Specifically, a ?? b
is processed as
follows:
- If A is not a nullable type or a reference type, a compile-time error
occurs.
- If A is a nullable type and an implicit conversion exists from b to
A0, the result type is A0. At
run-time, a is first evaluated. If a
is not null, a is unwrapped to type
A0, and this becomes the result.
Otherwise, b is evaluated and
converted to type A0, and this becomes
the result.
- Otherwise, if an implicit conversion exists from b to A, the result type is
A. At run-time, a is first evaluated.
If a is not null, a becomes the
result. Otherwise, b is evaluated and
converted to type A, and this becomes
the result.
- Otherwise, if b has a type B and an implicit conversion exists from A0 to
B, the result type is B. At run-time,
a is first evaluated. If a is not
null, a is unwrapped to type A0
(unless A and A0 are the same type)
and converted to type B, and this
becomes the result. Otherwise, b is
evaluated and becomes the result.
- Otherwise, a and b are incompatible, and a compile-time error occurs.
The second, third and fourth bullets are the relevant ones.
1 There's a philosophical discussion to be had about whether the compiler you happen to be using is the actual source of truth... is the truth about a language what it's meant to do or what it currently does?