可空types不是可空types?

我正在做一些可空types的testing,并没有像我预期的那样工作:

int? testInt = 0; Type nullableType = typeof(int?); Assert.AreEqual(nullableType, testInt.GetType()); // not the same type 

这也不起作用:

 DateTime? test = new DateTime(434523452345); Assert.IsTrue(test.GetType() == typeof(Nullable)); //FAIL DateTime? test = new DateTime(434523452345); Assert.IsTrue(test.GetType() == typeof(Nullable<>)); //STILL FAIL 

我的问题是为什么testInt.GetType()返回int,并且typeof(int?)返回true的可空types?

根据MSDN :

在Nullabletypes上调用GetType会导致在将types隐式转换为Object时执行装箱操作。 因此,GetType总是返回一个表示底层types的Type对象,而不是Nullabletypes。

当您打开一个可为空的对象时,只有底层的types被装箱。

再次,从MSDN :

装箱一个非null的可空值types会将值types框本身,而不是包装值types的System.Nullable。

进一步罗曼的正确答案,如果你想比较“真实”的types(即,没有隐式转换任何可空types为其基础types),那么你可以创build一个扩展方法,如下所示:

 public static class MyExtensionMethods { public static Type GetRealType<T>(this T source) { return typeof(T); } } 

然后尝试下面的testing:

 int? a = 0; Console.WriteLine(a.GetRealType() == typeof(int?)); // True Console.WriteLine(a.GetRealType() == typeof(int)); // False int b = 0; Console.WriteLine(b.GetRealType() == typeof(int)); // True Console.WriteLine(b.GetRealType() == typeof(int?)); // False DateTime? c = DateTime.Now; Console.WriteLine(c.GetRealType() == typeof(DateTime?)); // True Console.WriteLine(c.GetRealType() == typeof(DateTime)); // False DateTime d = DateTime.Now; Console.WriteLine(d.GetRealType() == typeof(DateTime)); // True Console.WriteLine(d.GetRealType() == typeof(DateTime?)); // False 

编辑…

为了完整性 – 并且由SLak的下面的注释提示 – 这是一个替代版本,当sourcenullNullable<>时,它只使用编译时types; 否则它使用GetType并返回运行时types:

 public static class MyExtensionMethods { public static Type GetRealType<T>(this T source) { Type t = typeof(T); if ((source == null) || (Nullable.GetUnderlyingType(t) != null)) return t; return source.GetType(); } } 

尽pipeC#假设值types存储位置拥有从System.ValueType派生的types实例,而System.ValueType派生自System.Object ,但这并不是真的。 从System.ValueType派生的每个types实际上代表了两种非常不同的东西:

  1. (对于原始types)直接表示数据的字节集合,或(对于非基元结构types)保存所有字段(公有和私有)的内容,但不包含任何types信息。
  2. 一个独立的堆对象,除了上述内容外,还包含一个对象头,其types派生自System.ValueType。

值types的存储位置保持第一个; 值types的堆对象保持第二个。

由于各种原因,微软决定Nullable<T>应该只支持第一次使用。 如果试图将types为Nullable<T>的存储位置传递给需要引用堆对象的代码,则如果HasValue为true,则系统将把该项转换为T ,否则只要传递null引用(如果HasValue为false) 。 虽然可以创buildNullable<T>types的堆对象,但是将值types的存储位置转换为堆对象的常规方法将永远不会生成。

还要注意的是,调用值存储位置上的GetType()并不会实际评估存储位置的types,而是会将该存储位置的内容转换为堆对象,然后返回结果对象的types。 由于typesNullable<T>存储位置被转换为T对象实例或null,因此对象实例中的任何内容都不会说明它所来自的存储位置是否为Nullable<T>

检查使用“is”运算符的简单方法是:

 (i is Nullable<int>) || (i is Nullable<long>) || (i is Nullable<float>) || (i is Nullable<short>) 

我想通过阅读这两个MSDN页面:

http://msdn.microsoft.com/en-us/library/ms366789(v=vs.90).aspx

http://msdn.microsoft.com/en-us/library/ms228597%28v=VS.90%29.aspx

干杯!