12

I was told that one of the many reasons strings were made immutable in the C# spec was to avoid the issue of HashTables having keys changed when references to the string keys altered their content.

The Dictionary<> type allows reference types to be used as a key. How does the dictionary avoid the issue of altered keys that lead to "misplaced" values? Is there a memberwise clone made of an object when used as a key?

Pierreten
  • 9,917
  • 6
  • 37
  • 45

6 Answers6

13

The Dictionary<TKey,TValue> type makes no attempt to protect against the user modifying the key used. It is purely left up to the developer to be responsible in not mutating the key.

If you think about this a bit this is really the only sane route that Dictionary<TKey,TValue> can take. Consider the implication of doing an operation like a memberwise clone on the object. In order to be thorough you'd need to do a deep clone because it will be possible for an object referenced in the key to also be mutated and hence affect the hash code. So now every key used in the table has it's full object graph cloned in order to protect against mutation. This would be both buggy and possibly a very expensive operation.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • 1
    Python though went another way and mutable data are not allowed as a cache key. http://www.udacity.com/view#Course/cs212/CourseRev/apr2012/Unit/207010/Nugget/251006 – Eugeniu Torica May 07 '12 at 20:11
10

If you're using a mutable reference type as a key, the default implementation of GetHashCode() will guarantee hash equality regardless of object state (i.e. the hash is tied to the reference, not the state). You're correct, however, that a mutable type with value equality semantics (where GetHashCode presumably depends on state) is a bad choice for a dictionary key.

Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • This is a good one. Thank you for remembering me that GetHashCode for a object by default is based on instance which I think saves developers a lot of time. – Eugeniu Torica May 07 '12 at 20:13
  • Mutable class types with value equality semantics seem like a bad idea anyway. While there are a few exceptions (e.g. `double`, `Decimal`, `List.Enumerator`, etc.), most types in .net implement `Equals(Object)` so as to indicate equivalence; since distinct mutable class-type items are never equivalent, they should never report themselves as `Equals` (the behavior of `List.Enumerator` stems from the fact that boxed and unboxed value types have different semantics, but are required to share the same `Equals` method). – supercat Oct 17 '12 at 16:25
6

The Dictionary<> class does nothing to protect itself against a mutable key object being changed. It's up to you to know whether or not the class you're using as a key is mutable, and to avoid it if possible.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
4

If a reference type does not override Equals/GetHashCode, a Dictionary using the default comparator won't care about any of the key objects' fields or properties, and thus won't notice or care if they change. It's simplest to think of the default GetHashCode method as returning a number related to an "object ID", and the default Equals method as comparing "object id's". Indeed, in a system limited to two billion or fewer objects, GetHashCode could simply return an object ID, but for various reasons it might do other things as well.

If the only part of an object that is examined by Equals or GetHashCode is the object ID, then for purposes of those functions, all objects are immutable. Once an object is created, it will always have the same ID, and that ID will never be used for any other object until all traces of the former object ID have vanished from the universe.

supercat
  • 77,689
  • 9
  • 166
  • 211
3

It does not avoid this situation. It's up to the calling code to enforce this:

As long as an object is used as a key in the Dictionary<TKey, TValue>, it must not change in any way that affects its hash value. Every key in a Dictionary<TKey, TValue> must be unique according to the dictionary's equality comparer. A key cannot be null, but a value can be, if the value type TValue is a reference type.

(From MSDN)

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
-1

Contrary to all answers, with introduction to Record classes, it is definetly possible to create mutable keys for dictionary. Record class will need to implement IEqualityComparer use HashCode struct. I can give out an example

N_E
  • 743
  • 10
  • 16