为啥 GetType 返回 System.Int32 而不是 Nullable<Int32>? [复制]

Posted

技术标签:

【中文标题】为啥 GetType 返回 System.Int32 而不是 Nullable<Int32>? [复制]【英文标题】:Why GetType returns System.Int32 instead of Nullable<Int32>? [duplicate]为什么 GetType 返回 System.Int32 而不是 Nullable<Int32>? [复制] 【发布时间】:2011-10-19 09:28:21 【问题描述】:

为什么这个sn-p的输出是System.Int32而不是Nullable&lt;Int32&gt;

int? x = 5;
Console.WriteLine(x.GetType());

【问题讨论】:

【参考方案1】:

GetType()object 的一个方法。 要调用它,Nullable&lt;T&gt; 结构必须被装箱。

您可以在 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

可空类型由 CLR 特殊处理;不可能有可空类型的盒装实例。 相反,对可空类型进行装箱将导致空引用(如果 HasValue 为 false)或装箱值(如果有值)。

因此,box System.Nullable&lt;System.Int32&gt; 指令产生一个装箱的Int32,而不是装箱的Nullable&lt;Int32&gt;

因此,GetType() 不可能永远返回Nullable&lt;T&gt;

要更清楚地看到这一点,请查看以下代码:

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

【讨论】:

【参考方案2】:

GetType() 不是虚拟的,因此仅在object 上定义。因此,要拨打电话,Nullable&lt;Int32&gt; 必须首先被装箱。不过,可空对象有特殊的装箱规则,因此只有 Int32 值被装箱,这就是报告的类型。

【讨论】:

Nullable(和其他结构,就此而言)不应该定义自己的 GetType 方法,这会影响 Object 的方法,有什么特别的原因吗?如果 Foo 是一个值类型,Foo.GetType() 应该需要创建一个新的堆对象来存储 Foo 的装箱内容,这似乎令人难以置信的愚蠢,而实际上该内容将被忽略。仅使用仅返回适当的 Type 对象的方法来隐藏 Foo.GetType() 不是更有效吗? @supercat 我不确定我是否有资格回答这个问题。我要说的一件事是,可空结构在很多方面都很愚蠢,因为它们基本上是事后附加的,而不是从一开始就被纳入语言中。我想,一般观点仍然成立,因为您还需要将int 变量装箱以调用GetType()。由于总是要加载重要的类型,因此这可能是空间/文档一致性的让步。也许 Eric Lippert 可以提供更多的启示。 @supercat GetType() 对于sealed 类型没有真正意义,因为您可以只使用typeof()Nullable&lt;T&gt; 和所有 structs 一样,是隐式密封的。如果调用GetType() 确实没有意义,当然,如果没有理由不这样做,它会起作用,但仅此而已,不要期望在优化方面付出太多努力。 @hvd:泛型的存在意味着有很多类型实际上是密封的,但是使用它们的代码不会静态地知道它们是密封的。不过,在我写完前面的问题之后,我发现了 GetType 如此工作的原因:每个声明的值类型实际上用 CLR 表示两种类型:未装箱的值类型和装箱的堆类型。前一种仅用于描述存储位置;后者用于对象实例。存储在值类型存储位置的东西只是位的组合,并且在类型系统之外。【参考方案3】:

你不能 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]

【讨论】:

需要标识符; “对象”是关键字 @slaks,谢谢...忘了解决这个问题。【参考方案4】:

因为“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;

【讨论】:

这不正确,SLaks。查看此处的文档:msdn.microsoft.com/en-us/library/…,其中说:“返回值类型:System.Type nullableType 参数的类型参数,如果 nullableType 参数是封闭的通用可空类型;否则为 null。” 你是对的;我记错了。但是,这并不能回答问题。 x int? 是的,但它位于 int? 变量中。您看到int 的原因是int? 被装箱到int Slaks,我想我们说的是同一件事。你只是说得更完整一点,但也有不必要的侵略作为你对 Nullable.GetUnderlyingType 的原始评论。

以上是关于为啥 GetType 返回 System.Int32 而不是 Nullable<Int32>? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我无法获取 GetType() 的 MethodBody?

SQL bigint 数据类型被 gettype() 视为字符串;功能。为啥?

Type.GetType()反射另外项目中的类时返回null的解决方法

Type.GetType()反射另外项目中的类时返回null的解决方法

Type.GetType()在跨程序集反射时返回null

Type.GetType()在跨程序集反射时返回null的解决方法