为什么一个 `null` 的 Nullable<T> 有哈希码?

39

有点奇怪的问题...

但是有人能给我一个为什么这是预期行为的理由吗?

这对我来说似乎完全不同寻常....


//Makes perfect sense
object o = null;
o.GetHashCode().Dump();

NullReferenceException:对象引用未设置为对象的实例。

//Seems very odd
int? i = null;
i.GetHashCode().Dump();

0

这显然是表示:

int? zero = 0;
int? argh = null;

zero.GetHashCode() == argh.GetHashCode(); //true

13
好问题。然而请注意,仅因为两个哈希码相等并不意味着这两个“实例”也相等。 - MakePeaceGreatAgain
有趣的是,将可空整数装箱为“object”,然后再次调用“GetHashCode”会导致NRE。 - MakePeaceGreatAgain
13
抱歉,我不太明白这个问题,但根据文档,Nullable<T>.GetHashCode 的说明是:如果 HasValue 属性为真,则返回 Value 属性的对象哈希码;如果 HasValue 属性为假,则返回零。由于此处的 HasValue 为假,因此预期答案应该是0。 - Equalsk
4
int? 是一个结构体,语法糖表示为 Nullable<int>。结构体始终具有哈希码,不会出现空引用异常。 - Hans Passant
10
可能性有2^32种哈希码和2^32 + 1 种可为空的int值,因此“int?”至少有两个具有相同哈希码。也许不难想象,哈希码相等的一对数是0和null。 - Eric Lippert
显示剩余2条评论
3个回答

48

这里的重点是

int? i = null;
i并没有被创建成null,而是(通过进行隐式转换)创建了一个没有值的Nullable<int>实例。这意味着该对象/实例不为null(由于Nullable<T>是一个结构体/值类型,它实际上不能为null),因此必须返回一个哈希码。
这也在此处有记录:

如果 HasValue 属性为 true,则返回 Value 属性返回的对象的哈希代码;否则返回零。


4
您可能需要解释一下,这是因为 Nullable 是一个值类型... - Zohar Peled
好的 - 感谢您链接到文档。我想一些语言设计师在同意实现之前可能争论了两个星期 - 真的,GetHashCode 应该以某种方式返回 Nullable<Int>() :) - Dave Bish
1
对象不能为 null,但如果你询问它是否为 null i == null,它会返回 true :-) - Magnus

15

int?实际上只是Nullable<int>的简写,这是一个包装int类型的结构体,以便允许它为空。Nullable可以与任何值类型一起使用。

因为Nullable实际上是一个结构体(它不能为null),所以它必须返回一个哈希码,并且通常它会返回该值的哈希码(可能是为了对值透明)。当该值为空时,默认情况下硬编码为返回0:

public override int GetHashCode() {
    return hasValue ? value.GetHashCode() : 0;
}

点击这里查看。


2
它可能会抛出相同的NullReferenceException,这样做在我看来更加正确。 - Dave Bish
10
如果它抛出了 NullReferenceException 并且你有一个 HashSet<int?>,你无法向其中添加空值。这将导致 NullReferenceException。这不是预期的行为 - 为什么要使用 HashSet<int?>,如果它不能接受空值?你应该使用 HashSet<int>。示例。如果不抛出异常,则更符合使用 Nullable 的总体框架,并更符合我的想法。 - ProgrammingLlama
4
ељУдљ†е∞ЖnullжЈїеК†еИ∞HashSet<string>дЄ≠жЧґдЉЪеПСзФЯдїАдєИпЉЯ - Arturo Torres Sánchez
3
所以,它是否抛出 NullReferenceException 并不重要,否则它将在空字符串的情况下失败。 - Arturo Torres Sánchez
1
@Arturo 我认输了。你是对的。HashSet 代码中也有相同的“如果为 null,则哈希码为 0”的逻辑,并且 null 可空类型在那里显然会被评估为 true。因此,即使 GetHashCode 抛出 NullReferenceException,它仍将按预期工作。 - ProgrammingLlama

8

根据文档说明,Nullable<T>.GetHashCode() 的行为是可以预测的:文档中写道:

如果 HasValue 属性为 true,则返回 Value 属性返回对象的哈希码;如果 HasValue 属性为 false,则返回零。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接