IEquatables实现仅在覆盖基本Equals时调用

时间:2011-09-30 15:49:17

标签: c# .net generics

我有以下课程

    class Product : IEquatable<Product>
{
    public Guid Id { get; set; }
    public bool Equals(Product other)
    {
        return Id.Equals(other.Id);
    }
}

如果我尝试创建列表中项目的唯一列表,如下所示

            Guid a = Guid.NewGuid();
        List<Product> listA = new List<Product>();
        listA.Add(new Product(){Id = a});

        List<Product> listB = new List<Product>();
        listB.Add(new Product()
        {
            Id = a
        });
        Debug.Assert(listA.Union(listB).Count()==1);

返回两个项目,直到我覆盖object.Equals方法,一旦我这样做,我的代码如下

class Product : IEquatable<Product>
{
    public Guid Id { get; set; }
    public bool Equals(Product other)
    {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.Id.Equals(Id);
    }

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

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

我的IEquatable Equals方法现在被调用,但是只有当我覆盖基本方法时,如果我在对象equals方法上放置一个断点,它永远不会被调用。

为什么会这样?

---- UPDATE

所以使用产品类

    class Product : IEquatable<Product>
{
    public Guid Id
    {
        get;
        set;
    }
    public bool Equals(Product other)
    {
        return Id.Equals(other.Id);
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }

}

如果删除了GetHashCode,那么Equals的IEquatable实现永远不会被击中我明白你应该一起实现Equals和GetHashCode,这是为什么?

2 个答案:

答案 0 :(得分:9)

问题出在原始实现中,您没有覆盖GetHashcode方法。引擎盖下Union使用Set<T>样式结构来删除重复项。此结构根据GetHashCode返回的值将对象放入存储区。如果哈希代码在相等对象之间不匹配(它必须这样做),那么它们可能被放入不同的桶中,并且从未与Equals进行比较

一般情况下,如果您实施IEquatable<T>,则应始终

  • 覆盖Object.Equals
  • 覆盖Object.GetHashCode

不这样做会让你陷入这样的境地。

注意,您的实现可以简化一点

class Product : IEquatable<Product>
{
  public Guid Id { get; set; }
  public bool Equals(Product other) 
  {
    if (ReferenceEquals(null, other)) {
      return false;
    }
    return other.Id == this.Id;
  }

  public override bool Equals(object obj) 
  {
    return Equals(obj as Product);
  }    

  public override int GetHashCode()
  {
    return Id.GetHashCode();
  }
}

答案 1 :(得分:3)

Enumerable.Union的文档说:

  

默认的相等比较器Default用于比较的值   实现IEqualityComparer(Of T)泛型的类型   接口。要比较自定义数据类型,您需要实现此目的   接口并提供自己的GetHashCode和Equals方法   类型。

您正在实施IEquatable。您需要实施IEqualityComparer