简体   繁体   English

记录类型:覆盖 EqualityContract 会破坏相等/哈希码匹配

[英]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中删除额外的属性会使GetHashCodeEquals “匹配”。

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 an int 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 of System.Collections.Generic.EqualityComparer<TN>.Default.GetHashCode(fieldN) where TN is the field type, and对于未继承的记录类型中的每个实例字段fieldNSystem.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM