2016-02-19 29 views
0

(1)我知道GetHashCode必须为两个对象返回相同的数字(如果它们相等)。Equalals中的SequenceEqual使GetHashCode中断

(2)我也知道,SequenceEqual比较一List的每个值,并Equals(list1, list2)将返回true只有list1list2是相同的实例。

所以,考虑下面的代码:

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); 
    } 
} 

我真的需要(用SequenceEqual(2))这种行为Equals,多为单元测试:使此代码Assert.AreEqual(classA1, classA2)工作。

但我的一些代码,可能是在这种情况下

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

hash1hash2因为破是不相等的。

所以在我的ClassA,(1)是不尊重。

什么是最好的解决办法:

  1. 变化ClassA.Equals方法使用Equals(this.SampleList, other.SampleList),而不是Enumerable.SequenceEqual(this.SampleList, other.SampleList),改变了所有的考试
  2. 创建另一个IEnumerable的实现,其中Equals压倒一切就像是SequenceEqual
  3. 修改ClassA.GetHashCode到请拨打GetHashCode关于所有清单项目
  4. 什么也不做
  5. 另一个?

回答

1

根本就不要将您的GetHashCodeSampleList:你不需要使用在GetHashCode()所有字段/属性。

例如:

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

甚至更​​好的使用只有SampleList的一些资料...的Count例如:

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

如果你真的想,你可以计算出在GetHashCode()元素SampleList。现在

,对于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); 
} 

(请不要写这样...使用foreach周期)在现在

+0

那么明显(我的某处大脑是**(1)**的倒数必须是真的)的想法。如果ClassA的设计不在大列表中(我只有10个不同的ClassA实例),并且我不需要性能,我们是否同意可以使用第二种解决方案(使用长度或其他字段)? – ZwoRmi

+0

@ZwoRmi是的。请注意,计算一个大的'SampleList'的哈希通常可能会非常长...因此,举例来说,您甚至可以“作弊”并仅在哈希中包含固定的子集...'(this.SampleList.Count * 397)^ this.SampleList.Take(5).Aggregate' – xanatos

+0

如果您完全忽略列表,那么碰撞率很可能会很高,导致使用散列码的任何情况都会导致性能很差。 – Servy