您的第一个条件无法编译的原因不是因为const
; 问题在于数据类型。aShort
是 a Nullable<Int16>
,如果您将其声明为正常的Int16
,它会正常工作
Int16 aShort = 5; // not nullable
Int32 anInt = 5;
Object o1 = test ? aShort : anInt; // does compile
当您拥有? (short?) : (int)
时,它无法进行转换,因为编译器不知道如何将 转换(short?)
为int
.
当您拥有? (short) : (int)
时,运行时会将 转换为short
以int
适应更大的数据类型。
然而,由于 C#编译器在处理整数时使用了一些特殊的魔法,第二个条件确实可以编译。当您拥有时,编译器会将 视为a ,因为您已将其声明为适合数据类型的值。然后在结果中隐式转换为 a 。const
? (short?) : (const int = 4)
const int
short
short
short
short?
如果你有? (short) : (const int = 4)
它的行为就像第一种情况一样,在运行时将 上转换short
为 a 。int
如果您有? (short?) : (short?)
作品,因为编译器知道如何将 a 隐式转换short
为 a short?
。
如果您在运行时查看结果类型,您实际上可以看到这一点。
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
事实上,如果你查看生成的 IL,o2
你会看到:
IL_001E: ldarg.0
IL_001F: ldfld UserQuery.test
IL_0024: brtrue.s IL_002E
IL_0026: ldc.i4.4 // your integer constant
IL_0027: newobj System.Nullable<System.Int16>..ctor // Notice the type here
IL_002C: br.s IL_0034
IL_002E: ldarg.0
IL_002F: ldfld UserQuery.aShort2
IL_0034: nop
IL_0035: box System.Nullable<System.Int16>
IL_003A: stloc.1 // o2