0

I'm making my own comparer, and for that overwriting the equals and GetHashCode .

Basically I'm comparing a list of values, and if all items in the list are equal I return true. But if the list is empty, or if an item in the list is empty string, I want to return false.

That is simple enough to do, but I'm wondering how to reflect this in the GetHashCode function? Since GetHashCode does not compare the items, but just generates a value from a single item it seems impossible to have two different hashcodes when I want the objects to not be equal.

How much does it matter that objects that are not equal have the same hashcode?

An example of what I have right now:

public class CustomComparer : IEqualityComparer<Dictionary<string, string>>
{
    List<string> keysToCompare = new List<string>();
    public bool Equals(Dictionary<string, string> d1, Dictionary<string, string> d2)
    {
        if (keysToCompare.Count == 0) return false;
        bool equals = true;
        foreach(string key in keysToCompare)
        {
            equals &= !string.IsNullOrWhiteSpace(d1[key]);
            equals &= d1[key].Equals(d2[key]);
        }
        return equals;
    }

    public int GetHashCode(Dictionary<string, string> d)
    {
        int hash = 3049;
        int prime = 31;
        foreach(string key in keysToCompare)
        {
            hash = hash * prime + d[key].GetHashCode();
        }
        return hash;
    }
}
Thediabloman
  • 134
  • 5
  • 2
    Could you provide *some examples*, please? Do I understand you correct that `Equals(new List(), new List()) == false`? If it is, you can't implement such `Equals` since `Equals` must be *reflexive*: `Equals(x, x) == true` – Dmitry Bychenko Feb 17 '21 at 10:18
  • I added an example of the code I want to make. The list "KeysToCompare" is defined outside the comparer and isnt always empty, but I want to handle the case where it could be empty. – Thediabloman Feb 17 '21 at 10:33
  • Please familiarize yourself with https://en.wikipedia.org/wiki/Pigeonhole_principle and then [duplicate](https://stackoverflow.com/questions/7425142/what-is-hashcode-used-for-is-it-unique) I picked should make sense. – Alexei Levenkov Feb 17 '21 at 10:34
  • Note that as @DmitryBychenko pointed out the current code in the question does not implement correct `Equals`, but that's should be easy fix with returning true for the same object (which is how Equals behaves by default for reference types). – Alexei Levenkov Feb 17 '21 at 10:40
  • `if (keysToCompare.Count == 0) return false;` condition **violates** `Equals` reflexivity (i.e. the principle that the instance *must be equal to itself*) – Dmitry Bychenko Feb 17 '21 at 10:40
  • That could be fixed by just adding a `if (d1 == d2) return true;` before the check for the the keysToCompare length check, right? Or is that just trying to circumvent the rule instead of adhering to it? :P – Thediabloman Feb 17 '21 at 10:46
  • "The list "KeysToCompare" is defined outside the comparer and isnt always empty". If this list isn't constant then 2 objects might be unequal at one point and suddenly become equal at another point? –  Feb 17 '21 at 10:47
  • I guess it should be something like `return keysToCompare.All(key => string.Equals(d1.TryGetValue(key, out string v1) ? v1 : null, d2.TryGetValue(key, out string v1) ? v2 : null));` Here we assume that if key *doesn't exist* the corresponding value is `null`. All the keys (and values) which are not in `keysToCompare` are ignored – Dmitry Bychenko Feb 17 '21 at 11:01
  • Technically yes. But in my case the list is defined in a configuration file that is not really updated continuously. Basically I'm trying to compare directed edges in a graph and allowing the user to define which values on the graph should decide equality. If for some reason the user decide to have no values that defines equality I want all edges to be different from each other. – Thediabloman Feb 17 '21 at 11:01
  • @DmitryBychenko Yes, but if for some reason the keysToCompare list was empty the All call would return true, right? – Thediabloman Feb 17 '21 at 11:05
  • @Thediabloman: yes in my guessed implementation if we have no keys to compare every comparison returns `true`. Corresponding hash code can be `return keysToCompare.Aggregate(0, (hash, key) => hash ^ (d.TryGetValue(key, out string s) ? s.GetHashCode() : 0));` – Dmitry Bychenko Feb 17 '21 at 11:06

0 Answers0