0

I have simple class only with public string properties.

public class SimpleClass
{
    public string Field1 {get; set;}
    public string Field2 {get; set;}
    public string Field3 {get; set;}
    public List<SimpleClass> Children {get; set;}

    public bool Equals(SimpleClass simple)
    {
        if (simple == null)
        {
            return false;
        }
        return IsFieldsAreEquals(simple) && IsChildrenAreEquals(simple);
    }

    public override int GetHashCode()
    {
        return RuntimeHelpers.GetHashCode(this); //Bad idea!
    }
}

This code doesn't return same value for equal instances. But this class does not have readonly fields for compute hash.

How can i generate correct hash in GetHashCode() if all my properties are mutable.

5
  • 2
    If a property is mutated, then the object is (presumably?) no longer equal to objects that it used to be equal to, so you just return a hash code based on the relevant properties to determine equality. Commented Dec 24, 2016 at 11:39
  • Why would the mutability of members be of importance for hash generation? You call GetHashCode() to determine a hash for that moment in time, not for the lifetime of that object. If you want the latter, then indeed you must make the properties read-only. Commented Dec 24, 2016 at 11:40
  • What does "correct" mean in your case? If all of your properties are mutable, and you use your SimpleClass as a key in a dictionary, what do you want to happen when one of those properties gets modified? If that causes the hash code to change, the dictionary will break. You may say "I won't do that", but you should be the one to actually say that, we shouldn't silently assume it. Commented Dec 24, 2016 at 11:42
  • compute hash once in constructor. put hash in readonly field. return the already computed hash from GetHashCode..... now no matter how your object changes. they will have hash of their first state. Commented Dec 24, 2016 at 11:42
  • 2
    @M.kazemAkhgary That means two objects that compare as equal may have different hash codes, which is not valid for .NET objects. Commented Dec 24, 2016 at 11:44

1 Answer 1

7

The contract for GetHashCode requires (emphasis mine):

The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state that determines the return value of the object's Equals method.

So basically, you should compute it based on all the used fields in Equals, even though they're mutable. However, the documentation also notes:

If you do choose to override GetHashCode for a mutable reference type, your documentation should make it clear that users of your type should not modify object values while the object is stored in a hash table.

If only some of your properties were mutable, you could potentially override GetHashCode to compute it based only on the immutable ones - but in this case everything is mutable, so you'd basically end up returning a constant, making it awful to be in a hash-based collection.

So I'd suggest one of three options:

  • Use the mutable fields, and document it carefully.
  • Abandon overriding equality/hashing operations
  • Abandon it being mutable
Sign up to request clarification or add additional context in comments.

5 Comments

My problem is ObjectListView library (TreeViewObject instance) using this class in some internal hashTable: I don't know where and how. So, i must use it's classes in hashtable. But when i trying compute hash using mutable fields - ObjectListView except with NullReferenceException. Is only possible solution makes SimpleClass immutable?
@gek0n A NullReferenceException suggests you've just implemented it badly.
Yes. I doesn't understand how i can implement it in right fast-compute way (coz if i must get hashes from all children as in equal method, it wi be very slow). Any suggestions?
@gek0n Well you haven't shown us any of your code, and we don't know what your performance requirements are. Basically, so can't help without a more specific question. (Your claim about computing hashes of children being "very slow" sounds like an expectation rather than the results of testing...)
anyway, your answer is correct, and i mark it as "accepted". My "very slow" is only expectation, coz i write some JsonEditor. And SimpleClass is a node in my own Json tree. It may have large deep of nesting, so i think iterate throw all children recurently is bad idea. I think i try implement SimpleClass as immutable type or try write "normal" GetHasCode() method. Thanx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.