The reason your first conditional code does not compile is not due to const ; the problem is with data types. aShort is Nullable<Int16> , if you declared it as regular Int16 , it will work just fine
Int16 aShort = 5; // not nullable Int32 anInt = 5; Object o1 = test ? aShort : anInt; // does compile
When do you have ? (short?) : (int) ? (short?) : (int) , it cannot perform the conversion because the compiler does not know how to convert (short?) to int .
When do you have ? (short) : (int) ? (short) : (int) , the runtime converts short to int to fit the larger data type.
However, the second condition is compiled thanks to some special magic that the C # compiler uses when processing const integers. When do you have ? (short?) : (const int = 4) ? (short?) : (const int = 4) , the compiler treats const int as short because you declared it as a value that will fit into the short data type. short then implicitly converted to short? as a result.
If you have ? (short) : (const int = 4) ? (short) : (const int = 4) , it behaves exactly the same as in the first case, increasing the conversion of short to int at run time.
If you have ? (short?) : (short?) ? (short?) : (short?) works because the compiler knows how to implicitly convert short to short? .
If you look at the types of results at runtime, you can see it.
Int16 aShort1 = 5; // not nullable Int16? aShort2 = 5; // nullable object o1 = test ? aShort1 : anInt; object o2 = test ? aShort2 : aConstInt; object o3 = test ? aShort1 : aConstInt; object o4 = test ? aShort1 : aShort2; o1.GetType() // System.Int32 o2.GetType() // System.Int16 o3.GetType() // System.Int32 o4.GetType() // System.Int16
In fact, if you look at the generated IL for o2 , you will see the following:
IL_001E: ldarg.0 IL_001F: ldfld UserQuery.test IL_0024: brtrue.s IL_002E IL_0026: ldc.i4.4