[英]Record types: overriding EqualityContract breaks the equality/hashcode match
Newly introduced record types allow to override EqualityContract
for type which makes possible to create a situation when two objects are equal but have different hashcodes which opposes guidelines for GetHashCode
overriding:新引入的记录类型允许覆盖类型的
EqualityContract
,这使得可以创建两个对象相等但具有不同哈希码的情况,这与GetHashCode
覆盖的准则相反:
If you override the GetHashCode method, you should also override Equals, and vice versa.
如果覆盖 GetHashCode 方法,则还应覆盖 Equals,反之亦然。 If your overridden Equals method returns true when two objects are tested for equality, your overridden GetHashCode method must return the same value for the two objects.
如果在测试两个对象是否相等时重写的 Equals 方法返回 true,则重写的 GetHashCode 方法必须为这两个对象返回相同的值。
public record Base(string Foo);
public record Child(string Foo, string Bar) : Base(Foo)
{
protected override Type EqualityContract => typeof(Base);
}
var b = new Base("Foo");
var c = new Child("Foo", "Bar");
Console.WriteLine(b == c); // True
Console.WriteLine(b.GetHashCode() == c.GetHashCode()); // False
While removing the extra property from Child
makes GetHashCode
and Equals
"match".从
Child
中删除额外的属性会使GetHashCode
和Equals
“匹配”。
Obviously this can be fixed with overriding GetHashCode
, but I wonder why overriding EqualityContract
does not automatically lead to having GetHashCode
return value "matching" Equals
implementation?显然,这可以通过覆盖
GetHashCode
来解决,但我想知道为什么覆盖EqualityContract
不会自动导致GetHashCode
返回值“匹配” Equals
实现? Or is there any other way to handle that except manual GetHashCode
override?或者除了手动
GetHashCode
覆盖之外还有其他方法可以处理吗?
As you can see in equality members part of records proposal ,正如您在记录提案的平等成员部分中看到的那样,
GetHashCode()
returns anint
result of a deterministic function combining the following values:GetHashCode()
返回结合以下值的确定性函数的int
结果:
For each instance field
fieldN
in the record type that is not inherited, the value ofSystem.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)
where TN is the field type, and对于未继承的记录类型中的每个实例字段
fieldN
,System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN)
的值,其中 TN 是字段类型,并且If there is a base record type, the value of base.GetHashCode();
如果有基记录类型,base.GetHashCode()的值; otherwise the value of
System.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract)
.否则
System.Collections.Generic.EqualityComparer<System.Type>.Default.GetHashCode(EqualityContract)
的值。
So, in your example GetHashCode
for Base
will be因此,在您的示例中
GetHashCode
for Base
将是
public override int GetHashCode()
{
return EqualityComparer<Type>.Default.GetHashCode(EqualityContract) + EqualityComparer<string>.Default.GetHashCode(Foo);
}
And for the Child
而对于
Child
public override int GetHashCode()
{
return base.GetHashCode() + EqualityComparer<string>.Default.GetHashCode(Bar);
}
For the inherited record the EqualityContract
isn't used for hash code calculation.对于继承的记录,
EqualityContract
不用于哈希码计算。 If an extra property Bar
is removed, the value from Base
is used and you'll get a hash values equality.如果删除了额外的属性
Bar
,则使用Base
中的值,您将获得哈希值相等。 So, overriding of GetHashCode
is needed.因此,需要覆盖
GetHashCode
。
This behavior is also observed using sharplab.io使用Sharplab.io也观察到了这种行为
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.