9

I have a Dictionary which I am comparing to another Dictionary (variables typed as IDictionary). Doing d1.Equals(d2) yields false. Writing my own code below yields true. Both are System.Collections.Generic.Dictionary. Am I missing something or does Dictionary not have an Equals implementation that compares keys/values?

private static bool DictEquals<K, V>(IDictionary<K, V> d1, IDictionary<K, V> d2)
{
    if (d1.Count != d2.Count)
        return false;

    foreach (KeyValuePair<K, V> pair in d1)
    {
        if (!d2.ContainsKey(pair.Key))
            return false;

        if (!Equals(d2[pair.Key], pair.Value))
            return false;
    }

    return true;
}
gturri
  • 13,807
  • 9
  • 40
  • 57
Mike Q
  • 22,839
  • 20
  • 87
  • 129

5 Answers5

12

Dictionary.Equals() uses the default Equals from Object, checking if the two objects are the same reference, as does all the other default collections. You're free to create your own subclass with value semantics, though that usually includes things being immutable as well.

SoftMemes
  • 5,602
  • 4
  • 32
  • 61
5

Probably the Equals method of the Dictionary class simply resorts to the default implementation inherited from Object, that is, it just compares the Dictionary object reference passed with its own reference. See here: Object.Equals reference

Joren
  • 14,472
  • 3
  • 50
  • 54
Konamiman
  • 49,681
  • 17
  • 108
  • 138
2

Assuming that two dictionaries, one being a SortedList<TKey, TValue> and one a Dictionary<TKey, TValue>, are compared for equality, should it really return true if the items are the same? That would be pretty bad, since they have different characteristics and features (the SortedList<,> for instance allows retrieval via index).

Also, equality and hash code are logically tied together. The hash code should be immutable, otherwise all hash based algorithms will not work. You cannot guarantee this when you're using the contents to check for equality. Therefore, the default implementation (checking if they are the same instance) is quite sane. You're free to create your own content equality comparison though.

Lucero
  • 59,176
  • 9
  • 122
  • 152
  • Fair point, my code above should do the usual identity + class compare check before comparing the content. – Mike Q Oct 30 '09 at 14:24
  • Right. However, this would still noe be a suitable replacement for Equals() because of the hashcode issue: if two objects are equal their hashcode must be equal, and the hash code must be immutable. In consequence, Equals() may not return true just because two collections are of the same type with the same contents, because they'll still have a different (immutable, sorry to stress it) hashcode. – Lucero Nov 01 '09 at 23:57
  • @Lucero: It's too bad that .NET only defines one set of virtual equivalence-relation methods, since most "immutable" class types hold references to objects that would be mutable *except that the references will never be exposed to anything that might mutate them* and it would be helpful if there were standard methods which those immutable wrapper classes could use to hash or check equality on their contents. – supercat Nov 03 '13 at 20:46
1

Others have mentioned that it is using the Object.Equals implementation, you can use the following to override it:

public class EqualsDictionary<T, T> : Dictionary<T, T>
{
    public override bool Equals(object obj)
    {
        //Place your comparison implementation here
    }
}
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
0

References in .NET may be used to encapsulate an object's identity, mutable aspects of its state, both, or neither, in addition to encapsulating immutable aspects of an object's state. In general, absent a particular reason to assume otherwise, .NET assumes that references to mutable objects are used for the purpose of encapsulating identity. It further assumes that in cases where code is comparing references without knowing what they represent, it is better to err on the side of reporting things unequal. As such, two references to mutable objects are generally considered equivalent if and only if they identify the same object, and mutable types are thus discouraged from overriding Equals to indicate anything else. Instead, code which uses references to encapsulate mutable state should use some means other than Object.Equals() to compare them.

supercat
  • 77,689
  • 9
  • 166
  • 211