【问题标题】:Proper way to write GetHashCode() when Equality Comparer is based on OR operation?当 Equality Comparer 基于 OR 操作时编写 GetHashCode() 的正确方法?
【发布时间】:2017-08-09 21:42:52
【问题描述】:

我正在尝试为具有 3 个字段的简单类编写平等比较器,如下所示:

public class NumberClass
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
}

NumberClass 的两个对象相等的条件是 Obj1.A == Obj2.A || Obj1.B == Obj2.B(换句话说,OR),Obj1 和 Obj2 是 NumberClass 的实例。

我可以轻松编写比较器的Equals(),如下所示,但我不知道如何处理我的GetHashCode() 方法。

public bool Equals(NumberClass x, NumberClass y)
{
    if (x.A == y.A || x.B == y.B)
        return true;
    else
        return false;
}

public int GetHashCode(NumberClass obj)
{
    return ???
}

如果我的相等条件是 AND 而不是 OR,我可以写我的 GetHashCode() 如下,taken from this SO answer

public int GetHashCode(NumberClass obj)
{
    unchecked
    {
        int hash = 17;
        if (obj != null)
        {
            hash = hash * 23 + obj.A.GetHashCode();
            hash = hash * 23 + obj.B.GetHashCode();
        }
        return hash;
    }
}

但这显然不适用于 OR,因为只有 AB 之一相等就足以使我的相等条件为真。

我能想到的一种解决方法是始终在GetHashCode() 中返回相同的值,这对于Distinct() 等LINQ 操作来说已经足够了,但我觉得应该有另一种方法,因为它有其自身的缺点。

处理这种情况的正确方法是什么?

附: 为了测试,假设我的 Main() 如下:

static void Main(string[] args)
{
    List<NumberClass> list = new List<NumberClass>();
    list.Add(new NumberClass { A = 1, B = 2, C = 3 });
    list.Add(new NumberClass { A = 1, B = 22, C = 33 });

    var distinct = list.Distinct(new NumberComparer());
    Console.ReadKey();
}

我希望distinct 只包含列表中的第一个元素。

【问题讨论】:

    标签: c# compare gethashcode iequalitycomparer object-comparison


    【解决方案1】:

    您的情况没有解决方案。您的对象违反了相等比较器工作所必需的假设,例如,它假设相等将是可传递的,但您的相等实现并非如此。

    只要你有这样的“模糊”相等性,你就无法使用任何基于哈希的算法。

    【讨论】:

    • 你能解释一下你的意思是什么它假设平等是传递性的
    • @Sach 如果 A 等于 B,B 等于 C,则 A 等于 C(如果相等是传递的)。你的情况不是这样。
    • 知道了,谢谢!好的,所以我想在这种情况下唯一的解决方法是在 GetHashCode() 中返回相同的值,或者干脆不使用比较器并进行老式比较。
    • @Sach 就像我说的那样,您无法使用使用散列进行相等比较的算法。此外,鉴于您对相等性的定义,“不同”的典型定义在概念上甚至没有意义,因此您不仅不能使用 .NET 定义,我什至不知道您将如何实现它(如,您需要确定您想要发生什么,因为考虑到您对平等的定义,典型的行为没有意义)。你需要从头开始写一些东西。
    • 我以前也从未使用过这种相等性。我问这个问题的原因是一位用户在对我的SO answers 之一的评论中问了这个问题,我很感兴趣。
    猜你喜欢
    • 2019-12-25
    • 2011-09-05
    • 2013-08-18
    • 1970-01-01
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多