C# 可空类型上的方法

C# 可空类型上的方法,c#,nullable,C#,Nullable,有人能解释一下为什么可以在null实例上调用方法吗 int? num = null; var s1 = num.ToString(); var s2 = num.HasValue; var s3 = num.GetHashCode(); var s4 = num.GetValueOrDefault(); var s5 = num.Value; // InvalidOperationException var s6 = num.GetType(); // NullReferenceExcept

有人能解释一下为什么可以在
null
实例上调用方法吗

int? num = null;

var s1 = num.ToString();
var s2 = num.HasValue;
var s3 = num.GetHashCode();
var s4 = num.GetValueOrDefault();

var s5 = num.Value; // InvalidOperationException
var s6 = num.GetType(); // NullReferenceException
我可以在调试模式下检查
num
是否为
null
,那么
ToString
方法或
HasValue
getter怎么可能在
null
实例上调用,但对于
Value
GetType
则不可能?它们都是
Nullable
类型上的方法或属性,还是不是

我自然希望
Value
getter返回
null
值,类似于
HasValue
返回
false
。我也希望,
GetType
返回
Nullable
类型信息,或者
num为int?
或者
num为Nullable
有效。为什么不起作用?如何检查
num
是否为可空类型

创建实例不会改变以下方面的任何内容:

Nullable<int> num = new Nullable<int>();
Nullable num=new Nullable();
幕后是什么?

Nullable
有一点编译器魔法,使它看起来好像有一个
null
值。但是没有。基本上,由于
Nullable
是一种值类型,因此它一开始就不能是
null
。它的可空性取决于是否存在值。这意味着您可以调用
HasValue
(这很重要,因为这是编译器在编写
num==null
时插入的)和其他不依赖于存在值的方法

关于几个具体问题:

  • ToString
    是一种实现,其工作原理与
    null
    值在字符串串联中使用时转换为字符串的方式类似,即生成空字符串。您也不希望
    ToString
    抛出
  • GetHashCode
    是将
    Nullable
    作为键放入字典或将其放入哈希集中所必需的。它也不应该抛出,所以当没有价值时,它必须返回一些合理的东西
  • 本文解释了一些基本概念
但是,在没有值的情况下访问该值是被禁止的。如注释中所示,这是调用
GetType
时隐式发生的情况:

编译器可以用
typeof(SomeT?
)悄悄地替换
nullableValue.GetType()
,这似乎是合乎逻辑的,但这意味着与其他编译器相比,它总是给出令人困惑的答案

object obj = nullableValue;
Type type = obj.GetType()
您可能希望它也能像这样工作,但是
obj.GetType()
总是返回
typeof(T)
(不是
typeof(T?
),或者抛出
NullReferenceException
,因为
T?
框指向
T
null
(并且您不能询问
null
它是什么类型)

编译器专门处理的结构映射有以下几点:

num == null         → !num.HasValue
num != null         → num.HasValue
num = null          → num = new Nullable<int>()
num = 5             → num = new Nullable<int>(5)
(int) num           → num.Value
(object) num        → (object) num.Value         // if HasValue
                    → (object) null              // if !HasValue
num==null→ !数值
num!=无效的→ 数值
num=null→ num=新的可空()
num=5→ num=新的可为空(5)
(int)num→ 数值
(对象)num→ (对象)num.Value//if HasValue
→ (对象)null//if!HasValue

还有对操作符的额外支持,最重要的是比较操作符与不可为null的
T
s以及处理潜在
null
值(如
)的各种操作符,但这是它的要点。

不是真正的答案,只是一个注释。你写道:

我自然希望
Value
getter返回
null


不!
Nullable
存在的原因就是为了保护您不必先检查就可以获得
null
值。

从文档开始。
Nullable.ToString
:“如果HasValue属性为true,则当前可为null对象的值的文本表示形式;如果HasValue属性为false,则为空字符串(“”)。
Nullable
是一个结构,因此实际上不能为
null
。这是编译器的特殊处理,使您能够执行
int?num=null
首先。主要是的副本。它已经解释了为什么
ToString
可以工作和
GetType
抛出
NullReferenceException
的核心问题,并解决了为什么
GetType
返回空引用异常的问题,请阅读。基本上,这是一种将
null
装箱的尝试。是的,装箱/取消装箱的基本行为解释了这一点。谢谢,但是我仍然认为请求一个类型并得到一个空的异常是不直观的。另外,
Value
是一个
t
必须是一个值类型,所以它不能是
null
。另外,
。Value
被键入为
t
,所以根据定义它永远不能返回
null
(因为您不能将
设为null
);值得注意的是
.GetValueOrDefault()
返回而不失败Joey:我想说的是,这正是有帮助的事情,也是创建
Nullable
的原因。我认为它的存在不是为了保护您,而是允许您在不能保存null值的类型上使用null值(从db或json端点获取),但是,是的,我稍微改变了对值getter的理解。基础值包含不能为null的原始值,因此通过值getter读取值不能返回null。这似乎是合乎逻辑的。