代码之家  ›  专栏  ›  技术社区  ›  Greg Smalter

为什么不呢。除了(LINQ)正确地比较事物?(使用IEquatable)

  •  24
  • Greg Smalter  · 技术社区  · 16 年前

    我有两个自己的引用类型对象集合,我为它们编写了自己的iequatable.equals方法,我希望能够对它们使用Linq方法。

    所以,

    List<CandyType> candy = dataSource.GetListOfCandy();
    List<CandyType> lollyPops = dataSource.GetListOfLollyPops();
    var candyOtherThanLollyPops = candy.Except( lollyPops );
    

    根据.except的文档,不传递IEqualityComparer应导致EqualityComparer.default用于比较对象。默认比较器的文档如下:

    “默认属性检查T类型是否实现System.IEquatable泛型接口,如果实现,则返回使用该实现的EquityComparer。否则,它将返回使用T提供的object.equals和object.getHashCode重写的EqualityComparer。”

    所以,因为我为我的对象实现了IEquatable,所以它应该使用它并工作。但是,它不起作用,直到我重写GetHashCode。实际上,如果我设置了一个断点,我的iequatable.equals方法就永远不会被执行。这让我觉得它符合B计划的文件。我知道重写gethashcode是一个好主意,无论如何,我可以让它工作,但我很不高兴它的行为方式与它自己的文档所述不一致。

    为什么它不按它说的去做?谢谢您。

    3 回复  |  直到 9 年前
        1
  •  20
  •   Community Mohan Dere    8 年前

    经过调查,事情并没有我想象的那么糟。基本上,当一切都正确实现(gethashcode等)时,文档是正确的,并且行为是正确的。但是,如果您尝试自己实现IEquatable,那么您的equals方法将永远不会被调用(这似乎是由于GetHashCode没有正确实现)。因此,虽然文档在技术上是错误的,但在您永远都不想做的边缘情况下是错误的(如果这次调查教会了我什么,那就是IEquatable是您应该原子地实现的一整套方法的一部分(按惯例,而不是按规则,很不幸))。这方面的好消息来源是:

    Is there a complete IEquatable implementation reference?

    http://msdn.microsoft.com/en-us/library/ms131190.aspx

    http://blogs.msdn.com/irenak/archive/2006/07/18/669586.aspx

        2
  •  10
  •   miradulo    9 年前

    界面 IEqualityComparer<T> 有以下两种方法:

    bool Equals(T x, T y);
    int GetHashCode(T obj);
    

    因此,这个接口的良好实现将实现这两个功能。linq扩展方法except依赖哈希代码,以便在内部使用字典或设置查找以确定要跳过哪些对象,因此需要正确的gethashcode实现。

    不幸的是,当你使用 EqualityComparer<T>.Default ,该类本身不提供良好的GetHashCode实现,并且在检测到该对象实现时,它依赖于所讨论的对象t类型来提供该部分。 IEquatable<T> .

    这里的问题是 IEquatable<T> 事实上没有声明 GetHashCode 因此,与 Equals 它声明的方法。

    所以你有两个选择:

    • 提供适当的 i质量公司<t> 实现两者的实现 等于 方法
    • 确保除了实现 IEquatable<T> 在您的对象上,实现适当的 方法
        3
  •  0
  •   Swanny    16 年前

    猜猜看,这是不同的课程吗?我认为默认情况下,iequatable只适用于同一类。所以它可以通过返回到对象.equal方法。