47

我正在对可空类型进行一些测试,但它并没有像我预期的那样工作:

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?) 返回真正的可空类型?

4

4 回答 4

57

根据MSDN

对 Nullable 类型调用 GetType 会导致在类型隐式转换为 Object 时执行装箱操作。因此 GetType 总是返回一个表示基础类型的 Type 对象,而不是 Nullable 类型。

当您装箱一个可为空的对象时,只有基础类型被装箱。

同样,来自MSDN

对非 null 可空值类型进行装箱是对值类型本身进行装箱,而不是对包装值类型的 System.Nullable 进行装箱。

于 2009-04-24T10:46:11.537 回答
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 的评论提示——这里有一个替代版本,它仅在sourceisnull或时使用编译时类型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();
    }
}
于 2009-04-24T12:14:02.217 回答
3

尽管 C# 假设​​值类型存储位置包含派生自 的类型的实例System.ValueType,而后者又派生自System.Object,但事实并非如此。派生自的每种类型System.ValueType实际上代表两种截然不同的事物:

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

值类型的存储位置是第一个;值类型的堆对象持有第二个。

由于种种原因,微软决定Nullable<T>只支持第一次使用。如果尝试将类型的存储位置传递给Nullable<T>期望对堆对象的引用的代码,系统会将该项转换为TifHasValue为 true,否则只需传递 null 引用 ifHasValue为 false。虽然有多种方法可以创建类型为 的堆对象Nullable<T>,但将值类型存储位置转换为堆对象的常规方法永远不会生成。

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

于 2012-04-02T20:23:34.920 回答
0

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

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

我发现 ti 阅读了这两个 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

干杯!

于 2013-11-12T12:38:37.397 回答