我正在使用可空类型进行一些测试,但它并没有像我预期的那样工作:
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?)返回真正的可空类型?
答案 0 :(得分:56)
根据MSDN:
在Nullable类型上调用GetType 导致拳击操作 当类型是隐式时执行 转换为Object。因此GetType 总是返回一个Type对象 代表基础类型,而不是 Nullable类型。
当你装入一个可以为空的对象时,只有底层类型被装箱。
再次,来自MSDN:
装箱非空可空值类型 列出值类型本身,而不是 包装值的System.Nullable 类型。
答案 1 :(得分:22)
除了Romain的正确答案之外,如果你想比较“真实”类型(即,没有隐式地将任何可空类型转换为其基础类型),那么你可以创建一个类似的扩展方法:
public static class MyExtensionMethods
{
public static Type GetRealType<T>(this T source)
{
return typeof(T);
}
}
然后尝试以下测试:
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
修改... 强>
为了完整性 - 并且由SLaks的评论提示 - 这是一个替代版本,当source
为null
或Nullable<>
时,仅使用编译时类型;否则它使用GetType
并返回运行时类型:
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();
}
}
答案 2 :(得分:3)
虽然C#假装值类型存储位置包含从System.ValueType
派生的类型的实例,而System.Object
又派生自System.ValueType
,但事实并非如此。从Nullable<T>
派生的每种类型实际上代表了两种截然不同的东西:
值类型的存储位置保持第一个;值类型的堆对象包含第二个。
出于各种原因,Microsoft决定Nullable<T>
应仅支持第一次使用。如果尝试将类型为T
的存储位置传递给期望引用堆对象的代码,则系统会在HasValue
为真的情况下将项目转换为HasValue
,否则如果Nullable<T>
为false,则简单地传递空引用。虽然有一些方法可以创建类型为GetType()
的堆对象,但是将值类型存储位置转换为堆对象的常规方法永远不会生成一个。
另请注意,在值存储位置调用Nullable<T>
实际上不会评估存储位置的类型,而是将该存储位置的内容转换为堆对象,然后返回该类型的存储位置。结果对象。由于类型T
的存储位置转换为Nullable<T>
的对象实例或转换为null,因此对象实例中的任何内容都不会说明它所来自的存储位置是{{1}}。< / p>
答案 3 :(得分:1)
检查使用“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
干杯!