使用IEquatable <t> </t>测试对等的对象集合

时间:2013-05-15 10:11:19

标签: c# tdd gethashcode iequatable

我有一个类,我已经实现了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。

Thans

1 个答案:

答案 0 :(得分:4)

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

  

覆盖Equals的类型也必须覆盖GetHashCode;否则,Hashtable可能无法正常工作。

即使代码可能无法在你的情况下运用,你仍然应该保留它。除了正确之外,它还可以帮助您测试集合的相等性,无论它们的顺序如何:

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