为什么这段代码的输出是
System.Int32
而不是Nullable<Int32>
?int? x = 5;
Console.WriteLine(x.GetType());
System.Int32
而不是Nullable<Int32>
?int? x = 5;
Console.WriteLine(x.GetType());
GetType()
是 object
的一个方法。
要调用它,必须将 Nullable<T>
结构体装箱。
您可以在 IL 代码中看到这一点:
//int? x = 5;
IL_0000: ldloca.s 00
IL_0002: ldc.i4.5
IL_0003: call System.Nullable<System.Int32>..ctor
//Console.WriteLine(x.GetType());
IL_0008: ldloc.0
IL_0009: box System.Nullable<System.Int32>
IL_000E: callvirt System.Object.GetType
IL_0013: call System.Console.WriteLine
HasValue
为false),或者装箱值(如果存在值)。box System.Nullable<System.Int32>
指令的结果是装箱的Int32
,而不是装箱的Nullable<Int32>
。GetType()
永远不可能返回Nullable<T>
。static void Main()
{
int? x = 5;
PrintType(x);
}
static void PrintType<T>(T val) {
Console.WriteLine("Compile-time type: " + typeof(T));
Console.WriteLine("Run-time type: " + val.GetType());
}
这会打印出来:
编译时类型:System.Nullable`1[System.Int32]
运行时类型:System.Int32
GetType()
不是虚拟的,因此仅在object
上定义。因此,要进行调用,必须首先将Nullable<Int32>
封箱。但是,Nullables具有特殊的封箱规则,因此仅封箱Int32
值,并报告该类型。
您不能 box 一个可空对象。
您可以像这样处理:
public static Type GetCompilerType<T>(this T @object)
{
return typeof (T);
}
int? x = 5;
Console.WriteLine(x.GetCompilerType());
// prints:
// System.Nullable`1[System.Int32]
因为 "5" 的类型是 int。
如果您想检测一个类型是否可为空,并获取其基础类型,请使用类似以下的代码:
public static Type GetActualType(Type type, out bool isNullable)
{
Type ult = Nullable.GetUnderlyingType(type);
if (ult != null)
{
isNullable = true;
return ult;
}
isNullable = false;
return type;
}
x
确实是一个int?
。 - SLaksint?
变量中。你看到 int
的原因是 int?
被装箱为 int
。 - SLaks
int
变量装箱才能调用GetType()
。由于这种情况下可能涉及到的类型始终会被加载,因此这可能是一种空间/文档一致性的让步。也许 Eric Lippert 可以提供更多的信息。 - dlevGetType()
对于sealed
类型来说并没有太多意义,因为你可以直接使用typeof()
。像所有的struct
一样,Nullable<T>
是隐式地被封闭的。如果调用GetType()
并不是很有意义,当然,如果没有任何理由不这样做,它会正常运行,但是请不要期望过多的优化工作。 - user743382