【问题标题】:Two objects being equal not regarded as distinct by LINQ两个相等的对象不被 LINQ 视为不同
【发布时间】:2016-09-08 19:32:04
【问题描述】:

我正在比较 Triangle 类型的两个对象,显然它们被认为是相等的(我实现了我的自定义 GetHaschCode 以及 Equal 方法和运算符)。

List<Triangle> triangles = ...;
bool same = triangles[0] == triangles[1];
// same is true

但是,当我在该列表中 Distinct() 时,它会保留所有元素(在我看来,这听起来像是通过引用进行比较,而不是通过我的自定义条件进行比较)。是这样吗?我该怎么办?

int countBefore = triangles.Count();
int countAfter  = triangles.Distinct().Count();
bool same = countBefore == countAfter;
// same is true, again

我遗漏了一些相当明显的东西,不是吗?

【问题讨论】:

  • 嗯,你能展示一个可重现的例子吗?听起来像是不正确的 GetHashCode 实现。
  • 这无济于事。如果您在Triangle 类中正确实现了EqualsGetHashCode 覆盖,则Distinct 将在没有IEqualtable&lt;Triangle&gt; 的情况下正常工作。如果你的GetHasCode 不正确,实现接口不会改变任何东西。只需发布课程代码,我们就会告诉您问题所在。看,如果你返回不同的哈希码,你的Equals方法根本不会被调用。
  • @IvanStoev 请将其作为回复发布,以便我接受。你说得对,伙计。您也可以从我上面的评论中提及一些内容,以使答案对后代更加有用。天才!
  • @KonradViltersten 谢谢你的朋友,但我已经看过很多次了,我很确定这是一个骗局。例如,stackoverflow.com/questions/371328/… 确实解释了这一切。
  • @IvanStoev 看起来是这样,是的。事实上,我可以看到我对其中的一些答案投了赞成票,所以我一定看过。但是,没有建立联系,呵呵。

标签: c# linq reference distinct equals


【解决方案1】:

您可以通过以下两种方式之一来做到这一点...

如 Andrew 所说,实现 IEquatable

public class Triangle : IEquatable<Triangle>
{
    bool IEquatable<Triangle>.Equals(Triangle other)
    {
        return Equals(other);
    }

    public override bool Equals(object obj)
    {
        //...
    }

    public override int GetHashCode()
    {
        //...
    }
}

或者您可以创建另一个实现IEqualityComparer(T) 的类并将其传递给 Distinct 方法调用。

public class TriangleComparer : IEqualityComparer<Triangle>
{
    public bool Equals(Triangle x, Triangle y)
    {
        return x.Equals(y);
    }

    public int GetHashCode(Triangle obj)
    {
        return obj.GetHashCode();
    }
}

【讨论】:

  • 我想知道它应该是 bool IEquatable.Equals(Triangle other) 还是只是 bool Equals(Triangle other) 像 Resharper建议。
  • 这取决于您是否希望能够通过首先强制转换为接口(显式实现)或不(隐式实现)来调用该方法 - 它也取决于使用情况,但因为它只会在 Distinct 调用中使用它可能会显式地实现它
【解决方案2】:

你需要在你的 Triangle 类中实现IEquatable(T) interface

来自Enumerable.Distinct() 文档:

默认相等比较器 Default 用于比较 实现 IEquatable 泛型接口的类型。到 比较自定义数据类型,需要实现这个接口和 为该类型提供您自己的 GetHashCode 和 Equals 方法。

【讨论】:

  • 我确实有 public override bool Equals(object input)。这还不够吗?同时拥有那个和 public bool Equals(Triangle other) 可能是多余的吗?
  • 我更新了我的答案。至于为什么在 C# 中会出现这种情况,请查看stackoverflow.com/a/2734941/743868
  • 嗯,文档是不正确的。如果该类实现IEquatable&lt;T&gt;,则默认相等比较器使用object.Equalsobject.GetHashCode 覆盖。在source 中查看ObjectEqualityComparer&lt;T&gt;
  • 恐怕还有什么问题。我在我的 Triangle 类中实现了 IEquatable 并按照 Resharper 的建议添加了第二个 Equal 方法。相同的结果,虽然...
  • 奇怪,我刚刚测试了一下,得到的结果和 Ivan 和 Ed 一样。您的 Equals 或 GetHashCode 方法可能有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
  • 2014-11-03
  • 2023-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多