Ok, before you get all mad because there are hundreds of similar sounding questions posted on the internet, I can assure you that I have just spent the last few hours reading all of them and have not found the answer to my question.
Background:
Basically, one of my large scale applications had been suffering from a situation where some Binding
s on the ListBox.SelectedItem
property would stop working or the program would crash after an edit had been made to the currently selected item. I initially asked the 'An item with the same key has already been added' Exception on selecting a ListBoxItem from code question here, but got no answers.
I hadn't had time to address that problem until this week, when I was given a number of days to sort it out. Now to cut a long story short, I found out the reason for the problem. It was because my data type classes had overridden the Equals
method and therefore the GetHashCode
method as well.
Now for those of you that are unaware of this issue, I discovered that you can only implement the GetHashCode
method using immutable fields/properties. Using a excerpt from Harvey Kwok's answer to the Overriding GetHashCode() post to explain this:
The problem is that GetHashCode is being used by Dictionary and HashSet collections to place each item in a bucket. If hashcode is calculated based on some mutable fields and the fields are really changed after the object is placed into the HashSet or Dictionary, the object can no longer be found from the HashSet or Dictionary.
So the actual problem was caused because I had used mutable properties in the GetHashCode
methods. When users changed these property values in the UI, the associated hash code values of the objects changed and then items could no longer be found in their collections.
Question:
So, my question is what is the best way of handling the situation where I need to implement the GetHashCode
method in classes with no immutable fields? Sorry, let me be more specific, as that question has been asked before.
The answers in the Overriding GetHashCode() post suggest that in these situations, it is better to simply return a constant value... some suggest to return the value 1
, while other suggest returning a prime number. Personally, I can't see any difference between these suggestions because I would have thought that there would only be one bucket used for either of them.
Furthermore, the Guidelines and rules for GetHashCode article in Eric Lippert's Blog has a section titled Guideline: the distribution of hash codes must be "random" which highlights the pitfalls of using an algorithm that results in not enough buckets being used. He warns of algorithms that decrease the number of buckets used and cause a performance problem when the bucket gets really big. Surely, returning a constant falls into this category.
I had an idea of adding an extra Guid
field to all of my data type classes (just in C#, not the database) specifically to be used in and only in the GetHashCode
method. So I suppose at the end of this long intro, my actual question is which implementation is better? To summarise:
Summary:
When overriding Object.GetHashCode() in classes with no immutable fields, is it better to return a constant from the GetHashCode
method, or to create an additional readonly
field for each class, solely to be used in the GetHashCode
method? If I should add a new field, what type should it be and shouldn't I then include it in the Equals
method?
While I am happy to receive answers from anyone, I am really hoping to receive answers from advanced developers with a sound knowledge on this subject.
Guid
, and use that for getting a hash code. I would personally try not to add aGuid
to a type just for use in a dictionary. Again alternatively, you could use something like an identity map to key for objects based on a detached immutable ID (again likely aGuid
so in effect the same result). Or again alternatively, don't amend items in the dictionary. Key them out, remove them, amend them, re-add them. – CarcanetEquals
methods to provide change notification in the application. By change notification I mean that I have aHasChanges
property that uses it like this:return originalState != null && !this.Equals(originalState);
. If I were to remove theEquals
andGetHashCode
implementations, then wouldn't I have to implementIEqualityComparer<T>
for every data type class? I have around 100 or more, so maybe I could do that in my next project. – HoxhaEquals
andGetHashCode
overrides? On theIEquatable<T>
Interface page on MSDN it says It should be implemented for any object that might be stored in a generic collection and then on theIEquatable<T>.Equals
Method page it says If you implement Equals, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<T>. – Hoxha