C# 为什么'null'可以为null<;T>;你有散列码吗?
有点奇怪的问题 但有谁能给我一个理由来解释为什么这会是预期的行为 这对我来说真的很奇怪C# 为什么'null'可以为null<;T>;你有散列码吗?,c#,nullable,C#,Nullable,有点奇怪的问题 但有谁能给我一个理由来解释为什么这会是预期的行为 这对我来说真的很奇怪 //Makes perfect sense object o = null; o.GetHashCode().Dump(); NullReferenceException:对象引用未设置为 反对 0 这显然意味着: int? zero = 0; int? argh = null; zero.GetHashCode() == argh.GetHashCode(); //true 这里的重点是 int? i
//Makes perfect sense
object o = null;
o.GetHashCode().Dump();
NullReferenceException:对象引用未设置为
反对
0
这显然意味着:
int? zero = 0;
int? argh = null;
zero.GetHashCode() == argh.GetHashCode(); //true
这里的重点是
int? i = null;
不创建变量i
,该变量为null
,而是(通过执行隐式转换)一个不具有值的null
实例。这意味着对象/实例不是
null
(由于null
是一种结构/值类型,它实际上不能是null
),因此必须返回哈希代码
这也有记录:
如果HasValue属性为true,则Value属性返回的对象的哈希代码;如果HasValue属性为false,则返回零
int?
实际上只是Nullable
的简写,这是一种结构,它包装int
类型以允许其为null。Nullable可用于任何值类型
因为Nullable实际上是一个结构(它不能为null),所以它必须为哈希代码返回一些内容,通常它会返回值的哈希代码(大概是为了尽可能对其中的值透明)。当该值为空时,默认情况下硬编码为返回0:
public override int GetHashCode() {
return hasValue ? value.GetHashCode() : 0;
}
请参阅。它看起来像是
Nullable.GetHashCode()
的记录行为:
如果
HasValue属性为true,如果HasValue属性为false,则为零
好问题。但是请注意,仅仅因为两个hashCode相等并不意味着两个实例也相等。有趣的是,将可为null的int装箱到
object
并再次调用GetHashCode
会产生一个NRE。这个问题超出了我的理解范围,请为我的无知道歉,但是为了我的利益,文档中提到了Nullable.GetHashCode
:如果HasValue属性为true,则Value属性返回的对象哈希代码;如果HasValue属性为false,则返回零。
。因为HasValue
这里是false
,所以我希望是0。这不是答案吗?int?是一个结构,语法是可为空的
。一个结构总是有一个散列码,并且从不产生NRE。有2^32
可能的散列码和2^32+1
可能的可为空整数,因此至少两个int?
必须具有相同的散列码。散列码相等的一对是0和null,这应该不会让人感到惊讶。您可能想解释一下,这是因为Nullable
是一种值类型……好的-感谢您链接到文档。我想象一些语言设计师在同意实现之前为此争论了两周-实际上,GetHashCode应该以某种方式返回Nullable():)对象不能为null,但如果您询问它是否为nullI==null
它将返回true:-)它可能会抛出相同的NullReferenceException,而不是-哪个IMO更正确,如果它抛出一个NullReferenceException,而您有一个哈希集
。不能向其添加空值。您将得到一个NullReferenceExection。这不是预期的行为-如果哈希集不能接受空值,为什么要使用它?您只需使用HashSet即可。如果它不抛出异常,在一般框架中更有意义,并且更适合使用Nullable,IMHO。@john,当您将null
添加到HashSet
时会发生什么?因此,它是否抛出NullReferenceException是无关紧要的,否则它将在null字符串情况下失败。@Arturo我承认。你说得对。代码中也有相同的“if null,hashcode is 0”逻辑,null null-nullable在这里的计算结果显然为true。因此,即使GetHashCode抛出了一个NullReferenceException,它仍然可以按预期工作。
public override int GetHashCode() {
return hasValue ? value.GetHashCode() : 0;
}