Skip to main content
 首页 » 编程设计

c#之使用 IEquatableT> 测试对象集合的相等性

2024年02月13日27tintown

我有一个类,我已经实现了 IEquatable<T>这样当我测试时我可以很容易地比较 IEnumerable使用以下调用收集这些对象:

Assert.IsTrue(expected.SequenceEqual(actual)); 

这目前运行良好,但我有一些挥之不去的疑虑。该类看起来像这样:

public class ThirdPartyClaim : IEquatable<ThirdPartyClaim> 
{ 
    // fields removed for question 
 
    public bool Equals(ThirdPartyClaim compareTo) 
    { 
        if (object.ReferenceEquals(this, compareTo)) 
        { 
           return true; 
        } 
 
        return this.ClaimId.Equals(compareTo.ClaimId) &&  
               this.Firstname.Equals(compareTo.Firstname) && 
               this.Lastname.Equals(compareTo.Lastname); 
    } 
 
   public override int GetHashCode() 
   {       
        int hashClaimId = this.ClaimId == null ? 0 : this.ClaimId.GetHashCode(); 
        int hashFirstname = this.Firstname == null ? 0 : this.Firstname.GetHashCode(); 
        int hashLastname = this.Lastname == null ? 0 : this.Lastname.GetHashCode(); 
 
        return hashClaimId ^ hashFirstname ^ hashLastname; 
    } 

我对覆盖 GetHashCode() 的理解是它用于比较指向类的同一实例的对象。在这种情况下(即使在未来)也不太可能需要这样做。

这种理解是否正确?如果正确,我可以安全地删除代码吗?

在我的单元测试中是否有更好的方法来比较这些对象的集合?

尽管我不得不使用 MSTest。

谢谢

请您参考如下方法:

覆盖 Equals 时需要覆盖 GetHashCode,否则基于哈希的容器可能无法正常工作。来自 Object.Equals 的文档:

Types that override Equals must also override GetHashCode; otherwise, Hashtable might not work correctly.

即使代码在您的情况下可能不会被执行,您仍然应该保留它。除了正确之外,它还可以帮助您测试集合的相等性,而不管它们的顺序如何:

Assert.IsTrue(expected.Except(actual).Count() == 0);     

我要对 GetHashCode 实现进行的一个更改是消除其对称性:目前,在对象中切换名字和姓氏会导致产生相同的哈希码。这是次优的。您可以通过将多个 int 乘以一个小素数来将它们组合成一个哈希码,例如31,然后将它们相加,如下所示:

public override int GetHashCode() 
{       
    int hashClaimId = this.ClaimId == null ? 0 : this.ClaimId.GetHashCode(); 
    int hashFirstname = this.Firstname == null ? 0 : this.Firstname.GetHashCode(); 
    int hashLastname = this.Lastname == null ? 0 : this.Lastname.GetHashCode(); 
 
    return 31*31*hashClaimId + 31*hashFirstname ^ hashLastname; 
}