GetHashCode override for a value wrapper. Is mutable ok?
-
Hi all, I am in the process of coding a generic wrapper class that adds some metadata and functionality to a generic value (unconstrained). I would prefer the equality of this wrapper to simply pass through to the underlying value. As a result the equals and getHashCode overrides are as follows
public override bool Equals(object obj)
{
return _value.Equals(obj);
}public override int GetHshCode()
{
return _value.GetHashCode();
}My concern here is that, as _value is not read-only, we now have a hash code that could potentially change. Am i right to be concerned about this with regard to housing the class within collections or using it within LINQ statements? (IIRC they make use of hashtables behind the scenes) Is there a better/safer approach? Thanks in advance
Pedis ex oris Quidquid latine dictum sit, altum sonatur
-
Hi all, I am in the process of coding a generic wrapper class that adds some metadata and functionality to a generic value (unconstrained). I would prefer the equality of this wrapper to simply pass through to the underlying value. As a result the equals and getHashCode overrides are as follows
public override bool Equals(object obj)
{
return _value.Equals(obj);
}public override int GetHshCode()
{
return _value.GetHashCode();
}My concern here is that, as _value is not read-only, we now have a hash code that could potentially change. Am i right to be concerned about this with regard to housing the class within collections or using it within LINQ statements? (IIRC they make use of hashtables behind the scenes) Is there a better/safer approach? Thanks in advance
Pedis ex oris Quidquid latine dictum sit, altum sonatur
This could, I think, potentially cause problems if you're using instances of this class in the key of dictionaries. But no more so than if you put _value in there instead, and there's not really a way to avoid it with mutable types. I think that you are only going to be sacrificing a bit of performance, not creating subtle bugs, because the .Net hashtable will look through all the items if it doesn't get a hash hit. Generally, you wouldn't put mutable things into collections as a key anyway. There are only two 'golden rules' of GetHashCode, to quote the documentation[^]:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values. 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. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.
You generally want to use as much of the state (which you compare within an Equals override) as possible to make the hash code uniqueness work well, and that means that if you mutate the object you change its hash code, which could cause a minor slowdown next time you look 'it' (i.e. something that matches it by Equals) up. So in conclusion, you're okay, but good question, and it's good practice not to mutate things (at least, not to mutate the parts of them which are part of their equality semantics) if they're being used as dictionary keys.
-
This could, I think, potentially cause problems if you're using instances of this class in the key of dictionaries. But no more so than if you put _value in there instead, and there's not really a way to avoid it with mutable types. I think that you are only going to be sacrificing a bit of performance, not creating subtle bugs, because the .Net hashtable will look through all the items if it doesn't get a hash hit. Generally, you wouldn't put mutable things into collections as a key anyway. There are only two 'golden rules' of GetHashCode, to quote the documentation[^]:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values. 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. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.
You generally want to use as much of the state (which you compare within an Equals override) as possible to make the hash code uniqueness work well, and that means that if you mutate the object you change its hash code, which could cause a minor slowdown next time you look 'it' (i.e. something that matches it by Equals) up. So in conclusion, you're okay, but good question, and it's good practice not to mutate things (at least, not to mutate the parts of them which are part of their equality semantics) if they're being used as dictionary keys.
-
Hi all, I am in the process of coding a generic wrapper class that adds some metadata and functionality to a generic value (unconstrained). I would prefer the equality of this wrapper to simply pass through to the underlying value. As a result the equals and getHashCode overrides are as follows
public override bool Equals(object obj)
{
return _value.Equals(obj);
}public override int GetHshCode()
{
return _value.GetHashCode();
}My concern here is that, as _value is not read-only, we now have a hash code that could potentially change. Am i right to be concerned about this with regard to housing the class within collections or using it within LINQ statements? (IIRC they make use of hashtables behind the scenes) Is there a better/safer approach? Thanks in advance
Pedis ex oris Quidquid latine dictum sit, altum sonatur
Then make it immutable / readonly; it probably should be anyway.
-
Then make it immutable / readonly; it probably should be anyway.
can't make it readonly im afraid. The class is providing a solution to firing off propertyChanged notifications without having to rely on hardcoded property name strings (it provides a 'single run per property' means by which property names are programatically derived) As a result the wrapper class is being used in place of a basic property backing field and therefore must be able to have its value changed as and when required. hope that makes sense
Pedis ex oris Quidquid latine dictum sit, altum sonatur
-
This could, I think, potentially cause problems if you're using instances of this class in the key of dictionaries. But no more so than if you put _value in there instead, and there's not really a way to avoid it with mutable types. I think that you are only going to be sacrificing a bit of performance, not creating subtle bugs, because the .Net hashtable will look through all the items if it doesn't get a hash hit. Generally, you wouldn't put mutable things into collections as a key anyway. There are only two 'golden rules' of GetHashCode, to quote the documentation[^]:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not compare as equal, the GetHashCode methods for the two object do not have to return different values. 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. Note that this is true only for the current execution of an application, and that a different hash code can be returned if the application is run again.
You generally want to use as much of the state (which you compare within an Equals override) as possible to make the hash code uniqueness work well, and that means that if you mutate the object you change its hash code, which could cause a minor slowdown next time you look 'it' (i.e. something that matches it by Equals) up. So in conclusion, you're okay, but good question, and it's good practice not to mutate things (at least, not to mutate the parts of them which are part of their equality semantics) if they're being used as dictionary keys.
BobJanova wrote:
I think that you are only going to be sacrificing a bit of performance, not creating subtle bugs, because the .Net hashtable will look through all the items if it doesn't get a hash hit.
No, it won't. Mutating an object that is used as a dictionary key will cause bugs. The correct solution is to remove the object from the dictionary, then mutate the key, then re-add it. Or better, just make the key immutable, remove the object from the dictionary, and re-add it using another key.