Noel
Noel

Reputation: 2091

What does System.Collections.Generic.Dictionary<T,T>.Equals actually do?

I ran into this today when unit testing a generic dictionary.

System.Collections.Generic.Dictionary<int, string> actual, expected;
actual = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
expected = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
Assert.AreEqual(expected, actual); //returns false

fails except when actual == expected (object references are the same). Obviously, actual.Equals(expected) returns false as well.

Fine, but if the implementation of System.Collections.Generic.Dictionary<int, string>.Equals only does reference equality, what's the point of IEquatable? In other words, why is there no baked-in way to do value equality for generic collections?

Edit Thanks for the responses so far. Obviously my example is using value types, but I think my complaint holds for all objects. Why can't a generic collection equality just be a union of equalities of its types? Unexpected behavior doesn't really cut it since there are separate provisions for finding reference equality. I suppose this would introduce the constraint of collections only holding object that implement IEquatable, as Konrad Rudolph points out. However, in an object like Dictionary, this doesn't seem too much to ask.

Upvotes: 2

Views: 2599

Answers (3)

Konrad Rudolph
Konrad Rudolph

Reputation: 545618

In other words, why is there no baked-in way to do value equality for generic collections?

Probably because it's hard to formulate in generic terms, since this would only be possible if the value type (and key type) of the dictionary also implemented IEquatable. However, requiring this would be too strong, making Dictionary unusable with a lot of types that don't implement this interface.

This is an inherent problem with constrained generics. Haskell provides a solution for this problem but this requires a much more powerful and complicated generics mechanism.

Notice that something similar is true for IComparable in comparison with containers, yet there is support for this, using Comparer<T>.Default if necessary.

Upvotes: 2

Lasse V. Karlsen
Lasse V. Karlsen

Reputation: 391396

Dictionary<TKey, TValue> does not implement IEquatable, as such there is no formal way to determine/know what comparing one such dictionary to another with the same contents would actually produce.

In fact, Dictionary<TKey, TValue> does not implement any of the comparison interfaces at all.

In my opinion, to have two objects compare themselves is a rather special thing, so it would've made much more sense to put that into an interface than just to put a default typically-unwanted implementation in the base Object class. It should've been a more advertised feature of a class than something every object can do, albeit not quite the way you expect it to.

But there you have it. It's there, and you need to know when it's going to be used.

Like in this case.

Upvotes: 1

Mike Scott
Mike Scott

Reputation: 12463

Dictionary<T,T>.Equals is inherited from Object.Equals and thus does a simple comparison of the object references.

Why do the generic collections not do value equality semantic? Because that may not be what you want. Sometimes you want to check if they're the same instance. What would the alternative do? Call Equals on each of the keys and values? What if these inherit Equals from Object? It wouldn't be a full deep comparison.

So it's up to you to provide some other semantic if and when necessary.

Upvotes: 2

Related Questions