Equality in C#
Pattern for implementing required operators to support '==', '!=', 'Equals()' and 'GetHashCode()' for a new reference or value type. Need to implement these methods together.
public override bool Equals(object rhs)
{
if (rhs == null) // this cannot be null
return false;
if (object.ReferenceEquals(this, rhs)
return true;
// Check for null values and compare run-time types.
if (this.GetType() != rhs.GetType())
return false;
return CompareFields(rhs as XXX);
}
private bool CompareFields(XXX p)
{ // Field by field comparison
return (this.field1 == this.field2) && ...;
}
public override int GetHashCode()
{ // Aim to get a unique number from the objects state
int tmp = ((int)(field1 << 16) + field2) ... ;
return tmp;
}
In general it is not recommended to override the '==' and '!=' operators for reference types. They should only be overriden for immutable types.
However here is a suitable implementation:
public static bool operator ==(XXX obj1, XXX obj2)
{
// IF obj1 is null
// so obj2 must be for equality
// ELSE obj1 is not null,
// compare it with obj2 using above Equals() operator
if (ReferenceEquals(obj1, null))
return ReferenceEquals(obj2, null);
else
return obj1.Equals(obj2);
}
public static bool operator !=(XXX obj1, XXX obj2)
{
return !(obj1 == obj2);
}
For VALUE types
public override bool Equals(object rhs)
{
if (rhs == null) // this cannot be null
return false;
return Equals(rhs as XXX);
}
public override bool Equals(XXX rhs)
{
return CompareFields(rhs);
}
private bool CompareFields(XXX p)
{ // Field by field comparison
return (this.field1 == this.field2) && ...;
}
public override int GetHashCode()
{ // Aim to get a unique number from the objects state
int tmp = ((int)(field1 << 16) + field2) ... ;
return tmp;
}
// For VALUE types
public static bool operator ==(XXX lhs, XXX rhs)
{
bool res = lhs.Equals(rhs);
return res;
}
public static bool operator !=(XXX lhs, XXX rhs)
{
return !(lhs==rhs);
}
Here is a Unit Test To Test the Equals operator Create 'x', 'y' and 'z' that are the same and an object 'a' that is not
TestEqualsOperator()
{
// Ensure all the XXX objects have the same constructor
// except the one called 'different'
XXX a = new XXX(...);
XXX x = new XXX(...);
XXX y = new XXX(...);
XXX z = new XXX(...);
XXX different = new XXX(...);
Debug.Assert(x.Equals(x) == true);
Debug.Assert(x.Equals(y) == y.Equals(x));
Debug.Assert((x.Equals(y) && y.Equals(z)) && x.Equals(z));
Debug.Assert(x.Equals(null) == false);
Debug.Assert(a.Equals(different) == false);
Debug.Assert(different.Equals(a) == false);
Debug.Assert(x.Equals(different) == false);
Debug.Assert(different.Equals(x) == false);
Debug.Assert(y.Equals(different) == false);
Debug.Assert(different.Equals(y) == false);
Debug.Assert(z.Equals(different) == false);
Debug.Assert(different.Equals(z) == false);
}
No comments:
Post a Comment