c# - 当相等比较器基于 OR 运算时,编写 GetHashCode() 的正确方法是什么?

标签 c# compare gethashcode iequalitycomparer object-comparison

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

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

我的两个 NumberClass 对象相等的条件是 if 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# - 当相等比较器基于 OR 运算时,编写 GetHashCode() 的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45601078/

相关文章:

c++ - C++设置唯一性和顺序

c# - CompreTo() 中的随机数与 GetHashCode() 的对比?

c# - 以编程方式更改天空盒 Material (c#)

java - 如何编辑我的比较方法

c# - Linux上的Web服务

c# - 如何在C#中检查字符串是否为特定格式

c# - .NET 唯一对象标识符

c# - Equals 和 GetHashCode 如何在匿名类型上实现?

C# Indexer 属性 - 有什么方法可以虚拟化 get 而不是 set 方法?

c# - SSRS : Master-detail report with two datasources