仅当基本 Equals 被重写时才调用 IEquatables 实现

发布于 2024-12-08 00:42:38 字数 1840 浏览 0 评论 0原文

我有以下类

    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 方法上放置断点,则永远不会调用它。

这是为什么呢?

----更新

因此,对于产品类

    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,这是为什么?

I have the following class

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

If i try and create a unique list of the items of a list as follows

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

two items are returned, this occurs until I override the object.Equals method, once i do this and my code is as follows

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

my IEquatable Equals method is now called, but only if i override the base method, furthermore if i put a breakpoint on the object equals method it is never called.

Why is this?

----UPDATE

So with the product class

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

}

If GetHashCode is removed, The IEquatable implementation of Equals is never hit I understand you should generally implement Equals and GetHashCode together, is this why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

×眷恋的温暖 2024-12-15 00:42:38

问题在于原始实现中您没有重写 GetHashcode 方法。在底层,Union 使用 Set 样式结构来删除重复项。该结构根据 GetHashCode 返回的值将对象放入存储桶中。如果相等对象之间的哈希码不匹配(这是必须的),那么它们可能会被放入不同的存储桶中,并且永远不会与 Equals 进行比较。

一般来说,如果您实现 IEquatable; 你应该总是

  • 覆盖 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();
  }
}

The problem is in the original implementation you're not overriding the GetHashcode method. Under the hood Union uses a Set<T> style structure to remove duplicates. This structure puts objects into buckets based on the value returned from GetHashCode. If the hash code doesnt't match up between equal objects (which it must do) then they can potentially be put in different buckets and never compared with Equals

In general if you implement IEquatable<T> you should always

  • Override Object.Equals
  • Override Object.GetHashCode

Not doing both will land you in situations like this.

Note, your implementation could be simplified a bit

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();
  }
}
谈情不如逗狗 2024-12-15 00:42:38

Enumerable.Union 的文档说:

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

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

Documentation for Enumerable.Union says:

The default equality comparer, Default, is used to compare values of
the types that implement the IEqualityComparer(Of T) generic
interface. To compare a custom data type, you need to implement this
interface and provide your own GetHashCode and Equals methods for the
type.

You're implementing IEquatable. You need to implement IEqualityComparer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文