3

dictionary.Keys.First().GetHashCode() == dictionary.Keys.First().GetHashCode() returns true dictionary.Keys.First() == dictionary.Keys.First() returns true

What's missing? Why can't the dictionary find this object?

Type of dictionary: Dictionary<ExceptionWrapper<Exception>, List<int>>.

Here is the implementation of ExceptionWrapper.Equals and ExceptionWrapper.GetHashCode:

public override int GetHashCode() {
  return (typeof(TException).FullName + exception.Message + exception.StackTrace).GetHashCode();
}

public override bool Equals(object obj) {
  return 
    obj is ExceptionWrapper<TException>
&& (obj as ExceptionWrapper<TException>).GetHashCode() == GetHashCode();
}
MushinNoShin
  • 4,695
  • 2
  • 32
  • 46
  • 2
    What is the type of `dictionary`? A code snippet would probably help as well. – dlev Jul 17 '13 at 22:18
  • Is `dictionary` being accessed from different threads? What is the key type? Does it override `Equals` inconsistently with the definition of `GetHashCode`? – Lee Jul 17 '13 at 22:21
  • There's no multithreading going on. – MushinNoShin Jul 17 '13 at 22:29
  • 1
    It's not a good style to create hash from a concatenated `string`. Your `Equals` is also very wrong; it returns `true` if two hashes are equal by accident. These are just comments, not the answer to your question. – Jeppe Stig Nielsen Jul 17 '13 at 23:18
  • Thanks for the feedback on equals. Yes, it is sloppy. I'd say I was in a hurry before but that's not a real excuse. – MushinNoShin Jul 19 '13 at 06:51

1 Answers1

4

The key was first added to the Dictionary<,> when it had one hash code. After that the object was "mutated" to give a state where the hash code is some new number.

The Dictionary<,> is therefore in an invalid state.

Do not mutate an object that might be a key in some hashtable somewhere, in a way the changes the hash code of that object.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • I don't /think/ there's any mutation going on. I'm going to try storing the hashcode in memory and see if it resolves the issue to be sure. Thanks for the idea. – MushinNoShin Jul 17 '13 at 22:26
  • If it was because of a state mutation, why doesn't `dictionary.containsKey(dictionary.Keys.First())` return true? – MushinNoShin Jul 17 '13 at 22:30
  • This seems like the most likely suspect... ContainsKey checks only the hashcode bucket from the object... so if the hashcode changes it is now looking in the wrong bucket for the object. – Kevin Jul 17 '13 at 22:32
  • 1
    @MushinNoShin Because the `Dictionary<,>` is completely corrupted when hash codes change. The key is ***lost***. Search for the key takes place in only one "bucket", the one corresponding to the new hash, but nothing is found since the item is located in another bucket. – Jeppe Stig Nielsen Jul 17 '13 at 22:34
  • That was it, thank you. Now I get to try to figure out how that exception changed. – MushinNoShin Jul 17 '13 at 22:38
  • 1
    @MushinNoShin If an exception being handled in a `catch` block is rethrown with the `throw` statement later in the block, that rethrow will modify the stack trace of the exception. – Jeppe Stig Nielsen Jul 17 '13 at 23:13