IEquatable中的条件<t> .Equals </t>

时间:2011-06-09 17:57:55

标签: c# linq comparison

我已经实现了IEquatable<T>来比较两个列表中的对象,但是我想这样做有条件地这样做:

public bool Equals(CustomerType other)
{

    if (this.Zipcode == "11111" || this.Zipcode == "22222" || this.Zipcode== "33333")
       {
          return this.FirstName.Equals(other.FirstName) && this.LastName.Equals(other.LastName) && this.MiddleName.Equals(other.MiddleName);
       }
       else
       {
          return this.FirstName.Equals(other.FirstName);
       }
}

这里出了点问题,它永远不会成为其他条件。有人可以告诉我哪里出错了吗?

- 使用 -

var v = listA.Except(listB).ToList();

- GetHashCode实现 -

    public override int GetHashCode()
    {
        unchecked
        {

            int hash = 17;         
            hash = hash * 23 + this.intField1.GetHashCode();         
            hash = hash * 23 + this.intField2.GetHashCode();         
            hash = hash * 23 + this.stringField3.GetHashCode();
            hash = hash * 23 + this.doubleField4.GetHashCode();
            hash = hash * 23 + this.doubleField5.GetHashCode();         

            return hash;
        }
    }

- 等于 -

    public override bool Equals(object obj) 
    {
        if (obj == null) return base.Equals(obj);
        if (obj is CustomerType ) 
        { 
            return this.Equals((CustomerType)obj); 
        } 
        else 
        { 
            return false; 
        } 
    }

- 实施例 -

ListA有2位客户:

Cust1: 名字 - “A” 姓氏 - “Z” MiddleName - “Y” ZipCode - “11111”

Cust2: 名字 - “B” 姓氏 - “X” MiddleName - “W” ZipCode - “44444”

ListB有2位客户:

Cust1: 名字 - “A” 姓氏 - “Z” MiddleName - “Y” ZipCode - “11111”

Cust2: 名字 - “B” 姓氏 - “G” MiddleName - “G” ZipCode - “44444”

这里当我说ListA.Except(ListB)时,它将CustA与FirstName,MiddleName,LastName进行比较,因为它属于Zipcode 11111而CustB只有FirstName,当我说ListB.Except(ListA)时同样适用。当前Equals实现中发生的事情是ListA.Except(ListB)可以正常工作,但是当我说ListB.Except(ListA)时,它会比较CustB的FirstName,LastName和Middlename。

2 个答案:

答案 0 :(得分:5)

我很确定你没有正确实现GetHashCode()。无论何时覆盖Equals,您都必须覆盖GetHashCode(),以便它们保持一致。

条件是,如果两个对象o1.Equals(o2)返回true,则GetHashCode的结果必须相同。

由于Except在内部使用散列集,因此GetHashCode()的实现与此相关。没有散​​列集,它的复杂性会从O(n)增加到O(n ^ 2),这显然是不可取的。

除此之外,Equals应该是对称的,而你的则不是。


查看您的GetHashCode()功能显然是错误的。它需要考虑Equals没有的字段。

每当您的代码进入then的{​​{1}}部分时,可能会考虑ifFirstNameLastName。当您的代码进入MiddleName部分时,else可能只考虑FirstName

GetHashCode()

但即使有public override int GetHashCode() { unchecked { if (this.Zipcode == "11111" || this.Zipcode == "22222" || this.Zipcode== "33333") { return FirstName.GetHashCode()*529+ LastName.GetHashCode()*23+ MiddleName.GetHashCode(); } else { return FirstName.GetHashCode(); } } 的实施,你仍然应该修复GetHashCode()的对称性

答案 1 :(得分:2)

关于你的equals和hashcode函数的对称性,并根据你在另一个答案的评论中所说的内容,我相信这是你需要的实现:

public bool Equals(CustomerType other)
{

    if ((this.Zipcode == "11111" || this.Zipcode == "22222" || this.Zipcode== "33333") &&
        (other.Zipcode == "11111" || other.Zipcode == "22222" || other.Zipcode== "33333"))
       {
          return this.FirstName.Equals(other.FirstName) && 
                 this.LastName.Equals(other.LastName) && 
                 this.MiddleName.Equals(other.MiddleName);
       }
       else
       {
          return this.FirstName.Equals(other.FirstName);
       }
}

对于GetHashCode:

public override int GetHashCode()
{
    if (this.Zipcode == "11111" || this.Zipcode == "22222" || this.Zipcode== "33333")
    {
        return FirstName.GetHashCode() ^ LastName.GetHashCode() ^ MiddleName.GetHashCode();
    }
    else
    {
        return FirstName.GetHashCode();
    }
}

ETA - 扩展一下 - 看来你的实现与单元的定义不一致。

假设略有不同(客户B和A的名字相同),请问自己以下问题:

  1. 客户A是否等于客户B?根据你的代码,答案是否定的。
  2. 客户B是否等于客户A?根据您的代码,答案是肯定的。
  3. 将客户A与客户B进行比较时,您的实施将使用第一个,最后一个&amp;中间名。但是,当将客户B与客户A进行比较时,您的实施将仅使用名字。这违反了fundamental definition of equality

      

    对称属性说明:

    * For any quantities a and b, if a = b, then b = a.
    

    任何依赖于Equals方法的内置函数都会假定其实现与相等的定义一致。由于您的实施不是,因此您违反了该假设,从而导致结果不一致。