简体   繁体   English

Equals中的SequenceEqual使GetHashCode损坏

[英]SequenceEqual in Equals makes GetHashCode broken

(1) I know that GetHashCode must return the same number for two objects if they are equal. (1)我知道,如果两个对象相等,则GetHashCode必须返回相同的数字。

(2) I also know that SequenceEqual compare each value of a List , and Equals(list1, list2) will return true only if list1 and list2 are the same instance. (2)我也知道SequenceEqual比较List每个值,并且只有list1list2是相同的实例时, Equals(list1, list2)才返回true。

So, consider this code : 因此,请考虑以下代码:

public List<ClassB> SampleList { get; set; }
public string Str { get; set; }
protected bool Equals(Uncorrectable other)
{
    return Enumerable.SequenceEqual(this.SampleList, other.SampleList) && string.Equals(this.Str, other.Str);
}

public override bool Equals(object obj)
{
    if (ReferenceEquals(null, obj)) { return false; }
    if (ReferenceEquals(this, obj)) { return true; }
    if (obj.GetType() != this.GetType()) { return false; }
    return this.Equals((ClassA) obj);
}

public override int GetHashCode()
{
    unchecked 
    { 
        return 
            ((this.SampleList != null ? this.SampleList.GetHashCode() : 0)*397) ^
            (this.Str != null ? this.Str.GetHashCode() : 0); 
    }
}

I really need this behavior( (2) using SequenceEqual ) for Equals , mostly for unit testing : make this code Assert.AreEqual(classA1, classA2) working. 我确实需要Equals这种行为( (2)使用SequenceEqual ),主要是用于单元测试:使此代码Assert.AreEqual(classA1, classA2)运行。

But some of my code is probably broken because in this case 但是我的某些代码可能已损坏,因为在这种情况下

int hash1 = new List<ClassB>().GetHashCode(); 
int hash2 = new List<ClassB>().GetHashCode(); 

hash1 and hash2 are not equal. hash1hash2不相等。

So in my ClassA , (1) is not respected. 因此,在我的ClassA ,不尊重(1)

What is the best solution : 最好的解决方案是什么:

  1. Change ClassA.Equals method to use Equals(this.SampleList, other.SampleList) instead of Enumerable.SequenceEqual(this.SampleList, other.SampleList) and change all my tests 更改ClassA.Equals方法以使用Equals(this.SampleList, other.SampleList)而不是Enumerable.SequenceEqual(this.SampleList, other.SampleList)并更改所有测试
  2. Create another IEnumerable implementation where the Equals overriding is like SequenceEqual 创建另一个IEnumerable实现,其Equals覆盖类似于SequenceEqual
  3. Modify ClassA.GetHashCode to call GetHashCode on all list items 修改ClassA.GetHashCode以在所有列表项上调用GetHashCode
  4. Do nothing 没做什么
  5. Another one? 另一个?

Simply don't base your GetHashCode on the SampleList : you don't need to use all the fields/properties in the GetHashCode() . 只需不要将您的GetHashCode基于SampleList :您不需要使用GetHashCode()中的所有字段/属性。

For example: 例如:

unchecked 
{ 
    return 
        (this.Str != null ? this.Str.GetHashCode() : 0); 
}

or even better use only some information of the SampleList ... The Count for example: 甚至最好只使用SampleList某些信息... Count例如:

unchecked 
{ 
    return 
        ((this.SampleList != null ? this.SampleList.Count.GetHashCode() : 0) * 397) ^
        (this.Str != null ? this.Str.GetHashCode() : 0); 
}

If you truly want, you can calculate the GetHashCode() on the elements of the SampleList . 如果你真的想,你可以计算GetHashCode()的的元素 SampleList

Now, for the C# obfuscation code tournament, 2016 edition: 现在,对于C#混淆代码竞赛,2016版:

unchecked
{
    return
        (397 * (this.SampleList != null ? 
            this.SampleList.Aggregate(0, (old, curr) => 
                (old * 397) ^ (curr != null ? curr.GetHashCode() : 0)) : 
            0)
        ) ^
        (this.Str != null ? this.Str.GetHashCode() : 0);
} 

(please don't write it that way... Use a foreach cycle) (请不要这样写...使用foreach循环)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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