Reputation: 2973
There is a passage from NHibernate
documentation:
Note: if you define an
ISet
of composite elements, it is very important to implementEquals()
andGetHashCode()
correctly.
What does correctly
mean there? Is it neccessary to implement those methods for all value objects in domain?
EXTENDING MY QUESTION
In the article Marc attached user Albic states:
It's actually very hard to implement
GetHashCode()
correctly because, in addition to the rules Marc already mentioned, the hash code should not change during the lifetime of an object. Therefore the fields which are used to calculate the hash code must be immutable.I finally found a solution to this problem when I was working with
NHibernate
. My approach is to calculate the hash code from the ID of the object. The ID can only be set though the constructor so if you want to change the ID, which is very unlikely, you have to create a new object which has a new ID and therefore a new hash code. This approach works best with GUIDs because you can provide a parameterless constructor which randomly generates an ID.
I suddenly realized what I've got inside my AbstractEntity
class:
public abstract class AbstractEntity<T> where T : AbstractEntity<T> {
private Nullable<Int32> hashCode;
public virtual Guid Id { get; protected set; }
public virtual Byte[] Version { get; set; }
public override Boolean Equals(Object obj) {
var other = obj as T;
if(other == null) {
return false;
}
var thisIsNew = Equals(this.Id, Guid.Empty);
var otherIsNew = Equals(other.Id, Guid.Empty);
if(thisIsNew && otherIsNew) {
return ReferenceEquals(this, other);
}
return this.Id.Equals(other.Id);
} // public override Boolean Equals(Object obj) {
public override Int32 GetHashCode() {
if(this.hashCode.HasValue) {
return this.hashCode.Value;
}
var thisIsNew = Equals(this.Id, Guid.Empty);
if(thisIsNew) {
this.hashCode = base.GetHashCode();
return this.hashCode.Value;
}
return this.Id.GetHashCode();
} // public override Int32 GetHashCode() {
public static Boolean operator ==(AbstractEntity<T> l, AbstractEntity<T> r) {
return Equals(l, r);
}
public static Boolean operator !=(AbstractEntity<T> l, AbstractEntity<T> r) {
return !Equals(l, r);
}
} // public abstract class AbstractEntity<T>...
As all components
are nested within entities
should I then implement Equals()
and GetHashCode()
for them?
Upvotes: 1
Views: 316
Reputation: 49261
The documentation for Equals and GetHashCode explain this well and include specific guidance on implementation for value objects. For value objects, Equals is true if the objects are the same type and the public and private fields are equal. However, this explanation applies to framework value types and you are free to create your own Equals by overriding it.
GetHashCode has two rules that must be followed:
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.
Upvotes: 1
Reputation: 62266
Correctly means that GetHashCode
returns the same hash code for the entities that are expected to be equal. Because equality of 2 entities is made by comparison of that code.
On the other side, that means that for entities that are not equal, the uniqueness of hash code has to be guaranteed, as much as it possible.
Upvotes: 1