When you do a dictionary lookup, this is the order things happen:
- The dictionary uses TKey.GetHashCode to compute a hash for the bucket.
- It then checks all of the hashes using that bucket, and calls Equals on the individual objects, to determine a match.
If the buckets never match (because GetHashCode wasn't overwritten), then you'll never call Equals. This is part of why you should always implement both if you implement either - and you should override both functions (more meaningfully than just calling base.GetHashCode()) if you want to use your object in a hashed collection.
If you're implementing a class, you should implement a GetHashCode routine that returns the same hash code for items that are Equal. Ideally, you want to return a different hash code for items that are not equal whenever possible, as this will make your dictionary lookups much faster.
You should also implement Equals in a way that checks for equal instances correctly.
The default implementation for classes (reference types) just compare the reference itself. Two instances, with exactly the same values, with return false on Equals (since they have different references), by default. Multiple instances will always also return a different hash code, by default.