可为null的布尔值上的GetType
本文关键字:GetType 布尔值 可为 null | 更新日期: 2023-09-27 17:58:20
当我在MicrosoftMSDN 上发现这篇文章时,我正在研究可为null的布尔
如何:识别可为null的类型(C#编程指南)
您可以使用C#typeof运算符来创建一个表示可为null类型的Type对象。
所以我试着用一个可以为null的bool:进行检查
Console.Write(typeof(bool?)); //System.Nullable`1[System.Boolean]
MSDN上的文章说
您还可以使用System.Reflection命名空间的类和方法来生成表示可为null类型的Type对象。但是,如果您试图在运行时使用GetType方法或is运算符从Nullable变量中获取类型信息,则结果是表示基础类型的type对象,而不是Nullable类型本身。
对可为null的类型调用GetType会导致在该类型隐式转换为Object时执行装箱操作因此,GetType总是返回一个表示基础类型的Type对象,而不是Nullable类型
如果这是真的,无论我使用可为null的布尔还是常规布尔,我都希望从.GetType()
中得到相同的结果。但事实并非如此:
bool a = new bool();
Console.Write(a.GetType()); //Prints System.Boolean
bool? b = new bool?();
Console.Write(b.GetType()); //Exception!
发生的异常:
BoolTest.exe 中发生类型为"System.NullReferenceException"的未处理异常
附加信息:对象引用未设置为对象的实例。
但是对象引用被设置为对象的实例。这个错误的原因可能是什么?
您的实际问题似乎是:
通过使用默认构造函数(例如
bool? b = new bool?();
)将Nullable<T>
初始化为默认值,为什么访问b
的成员(如GetType()
)会抛出NullReferenceException
?new
不是总是返回一个值,所以b
不可能真的是null
吗?
嗯,是和否。Nullable<T>
有点特别。来自C#规范:
4.1.10可为空的类型
[…]
可为null类型T的实例?具有两个公共只读属性:
- 布尔类型的HasValue属性
- T类型的Value属性
HasValue为true的实例称为非null。非null实例包含一个已知值,value返回该值。HasValue为false的实例称为null。null实例具有未定义的值。尝试读取null实例的值会引发System.InvalidOperationException。
所以,是的,bool? b = new bool?();
确实返回了一个实例:一个你只能调用HasValue
的实例。由于它返回false
,你不能对该实例做太多其他事情。
然后是下一个相关部分:
4.3.1装箱转换
如果可为null类型的值是null值(HasValue为false),则装箱会生成null引用
这在MSDN中也有解释:Boxing Nullable Types(C#编程指南):
只有当对象为非null时,才会对基于可为null类型的对象进行装箱。如果HasValue为false,对象引用将被指定为null,而不是装箱。
进一步了解规格:
11.3.5装箱和拆箱
当结构类型重写从System.Object继承的虚拟方法(如Equals、GetHashCode或ToString)时,通过结构类型的实例调用虚拟方法不会导致装箱。
GetType()
未被Nullable<T>
覆盖,因此将发生装箱。当您在结构上调用GetType()
或任何非重写方法时,在调用该方法之前,该结构将被装箱到对象中。在Nullable<T>
为空的情况下,装箱操作的结果将是(object)null
。因此出现了例外。
另请参阅在.NET中对值类型调用方法会导致装箱吗?。
因此,为了回答您的问题:
b
是而不是null,它持有Nullable<bool>
,其中HasValue
指示false
- 对其调用未重写的
GetType()
方法会导致Nullable<bool>
结构被装箱,以便访问底层方法object.GetType()
- 这个装箱操作实际上并不装箱,只是简单地返回
(object)null
- 最后,您调用
((object)null).GetType()
,它抛出您遇到的NullReferenceException
如果你真的在寻找一段可以返回任何变量类型的代码,即使是空的Nullable<T>
,也可以使用这样的代码:
Type GetType<T>(T obj)
{
return typeof(T);
}
你可以这样称呼它:
Console.WriteLine(GetType(b));
您在NULL
引用上调用GetType
(装箱不带值的Nullable Type的结果)。
bool? b = new bool?();
相当于bool? b = null;
尝试此操作以获得正确的结果:
bool? b = new bool?(false);
Console.Write(b.GetType()); // System.Boolean
该文档意味着,如果在具有值(Not Null)的Nullable
对象上成功调用GetType()
。您得到的基本类型是System.Boolean
。但是不能使用NULL
引用调用任何方法,这是适用于任何引用类型的一般规则。
要清除= null
和new bool?()
之间的等价点,请检查此Fiddle。两者都生成相同的IL:
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<bool>
和
IL_0009: ldloca.s V_1
IL_000b: initobj valuetype [mscorlib]System.Nullable`1<bool>