Proper way to write GetHashCode() when Equality Co

2019-07-29 05:52发布

问题:

I'm trying to write an Equality Comparer for a simple class with 3 fields, like so:

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

My condition for two objects of NumberClass to be equal is if Obj1.A == Obj2.A || Obj1.B == Obj2.B (in other words, OR), Obj1 and Obj2 being instances of NumberClass.

I can easily write the Equals() of my comparer as follows, but I don't know what to do with my GetHashCode() method.

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 ???
}

If my condition for equality was AND instead of OR, I could write my GetHashCode() as follows, 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;
    }
}

But that obviously wouldn't work for OR since only one of A or B being equal is sufficient for my equality condition to be true.

One workaround I could think of is always returning the same value in GetHashCode() which would be sufficient for LINQ operations such as Distinct(), but I feel like there should be another way as that has its own shortcomings.

What's the proper way to handle this situation?

P.S. For testing, imagine my Main() is the following:

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

I expect distinct to contain only the first element in the list.

回答1:

There is no solution for your situation. Your objects violate assumptions that are necessary for an equality comparer to work, for example, it assumes that equality is going to be transitive, but that's not true of your implementation of equality.

You simply won't be able to use any hash-based algorithms so long as you have "fuzzy" equality like that.