可空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的下面的注释提示 – 这是一个替代版本,当source
为null
或Nullable<>
时,它只使用编译时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实际上代表了两种非常不同的东西:
- (对于原始types)直接表示数据的字节集合,或(对于非基元结构types)保存所有字段(公有和私有)的内容,但不包含任何types信息。
- 一个独立的堆对象,除了上述内容外,还包含一个对象头,其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
干杯!