GetType在Nullable布尔值上

Dan*_*iel 4 c# null boolean

当我在Microsoft MSDN上发现这篇文章时,我正在研究可空的bool

如何:识别可空类型(C#编程指南)

您可以使用C#typeof运算符创建表示Nullable类型的Type对象.

所以我尝试用可空的布尔检查:

Console.Write(typeof(bool?)); //System.Nullable`1[System.Boolean]
Run Code Online (Sandbox Code Playgroud)

MSDN上的文章说

您还可以使用System.Reflection命名空间的类和方法来生成表示Nullable类型的Type对象.但是,如果尝试通过使用GetType方法或is运算符在运行时从Nullable变量获取类型信息,则结果是一个Type对象,它表示基础类型,而不是Nullable类型本身.

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

如果这是真的,我希望得到相同的结果,.GetType()无论我使用可空的bool还是常规的bool.但这不是发生的事情:

    bool a = new bool();
    Console.Write(a.GetType()); //Prints System.Boolean

    bool? b = new bool?();
    Console.Write(b.GetType()); //Exception!
Run Code Online (Sandbox Code Playgroud)

发生的例外情况:

BoolTest.exe中出现未处理的"System.NullReferenceException"类型异常

附加信息:未将对象引用设置为对象的实例.

但是对象引用设置为对象的实例.可能是导致此错误的原因是什么?

Zei*_*kki 6

你正在调用GetType一个NULL引用(装箱一个没有值的可空类型的结果)。

bool? b = new bool?(); 相当于 bool? b = null;

试试这个以获得正确的结果:

bool? b = new bool?(false);
Console.Write(b.GetType()); // System.Boolean
Run Code Online (Sandbox Code Playgroud)

该文档意味着如果您GetType()成功调用Nullable具有值(非空)的对象。你得到的底层类型是System.Boolean. 但是您不能使用NULL引用调用任何方法,这是适用于任何引用类型的一般规则。

要清除= null和之间的等价点new bool?(),请检查此Fiddle。两者都生成相同的 IL:

IL_0001:  ldloca.s   V_0
IL_0003:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
Run Code Online (Sandbox Code Playgroud)

IL_0009:  ldloca.s   V_1
IL_000b:  initobj    valuetype [mscorlib]System.Nullable`1<bool>
Run Code Online (Sandbox Code Playgroud)

  • _"bool? b = new bool?(); 等价于 bool?b = null;"_ - 不,不是。`new` 永远不会返回 `null`。此外,`bool?b = new bool?(false)` 与 `bool? b = new bool?()`。前者确实持有 bool 值,后者没有。 (2认同)
  • 我的立场更正了,两者确实都被编译为`initobj`。所以虽然 `Nullable&lt;T&gt;` 是一个结构体,你可以用 `null` 初始化它,但它实际上不是 null,因为 `bool? 富 = 空;foo.HasValue` 不会抛出。可空值很奇怪。 (2认同)

Cod*_*ter 6

你的实际问题似乎是:

Nullable<T>例如bool? b = new bool?();,通过使用其默认构造函数将a初始化为其默认值,为什么访问b的成员如GetType()throw a NullReferenceException?并不new总是返回一个值,所以b真的不是null吗?

嗯,是的,不.Nullable<T>有点特别.来自C#规范:

4.1.10可空类型

[...]

可空类型T的实例?有两个公共只读属性:

  • bool类型的HasValue属性
  • T类型的Value属性

HasValue为true的实例被称为非null.非null实例包含已知值,Value返回该值. HasValue为false的实例被称为null.null实例具有未定义的值.尝试读取null实例的值会导致抛出System.InvalidOperationException.

所以是的,bool? b = new bool?();确实会返回一个实例:一个你只能调用的实例HasValue.由于它返回false,你不能对该实例做很多其他事情.

然后是下一个相关部分:

4.3.1拳击转换

如果它是空值(HasValue为false),则为可空类型的值装箱会产生空引用

MSDN中也解释了这一点 :Boxing Nullable Types(C#编程指南):

如果对象为非null,则仅基于可空类型的对象进行装箱.如果HasValue为false,则将对象引用分配为null而不是装箱.

进一步了解规格:

11.3.5拳击和拆箱

当结构类型覆盖从System.Object继承的虚方法(例如Equals,GetHashCode或ToString)时,通过struct类型的实例调用虚方法不会导致发生装箱.

GetType()没有被覆盖Nullable<T>,所以拳击会发生.当您GetType()在结构上调用或任何未重写的方法时,在调用该方法之前,该结构将被装箱到一个对象.在null的情况下,Nullable<T>该装箱操作的结果将是(object)null.因此例外.

另请参阅在值类型上调用方法是否导致在.NET中装箱?.


那么,回答你的问题:

  • b不是空,它拥有一个Nullable<bool>带有HasValue指示false.
  • 在其GetType()上调用非重写方法会导致对Nullable<bool>结构进行装箱以访问基础方法object.GetType().
  • 这个拳击操作实际上没有框,但只是返回(object)null.
  • 最后,你正在打电话((object)null).GetType(),这会引发NullReferenceException你的遭遇.

如果您实际上正在寻找可以返回任何变量类型的代码,甚至是null Nullable<T>,请使用以下内容:

Type GetType<T>(T obj) 
{ 
    return typeof(T); 
}
Run Code Online (Sandbox Code Playgroud)

你可以这样打电话:

Console.WriteLine(GetType(b));
Run Code Online (Sandbox Code Playgroud)