Ok, I have a class within which I want to over-ride the equality operator, so I have the following code:
/// <summary>
/// Over-ride of the equality operator.
/// </summary>
/// <param name="credential1">The left hand object to test for equality.</param>
/// <param name="credential2">The right hand object to test for equality.</param>
/// <returns>True if the objects are equal.</returns>
public static bool operator ==(KnownServerCredential credential1, KnownServerCredential credential2)
{
// ok check if either is null
bool cell1Null = Equals(null, credential1);
bool cell2Null = Equals(null, credential2);
// if both are, then it's true
if (cell1Null && cell2Null)
{
return true;
}
// if only one is, then how can they be the same?
if (cell1Null || cell2Null)
{
return false;
}
// neither are - so we can now go to full on equality
return credential1.IsEqualTo(credential2);
}
This works fine, and I’m happy with it. However, static analysis tools (both Resharper and the VS2010 Code Analysis) swear blind that the last line could throw a null reference exception, because of the way I am checking for null in the top two lines. If I change the top two lines from Equals(null, credentialX) to credentialX == null then the static analysis tools are happy, but it creates a stack overflow exception, because I am then recursively calling the equality over-ride. I can have the best of both worlds by using (object)credentialX == null, but that doesn’t seem like the cleanest way of doing it.
So the simple question is, am I missing something, or is cast-and-compare the best way to achieve what I’m looking for?
There are two ways of checking whether a pair of objects are equal: reference equality and structural/value equality. Reference equality is the default for all reference types (classes), and structural equality is the default for all value types (but the default implementation is not optimal). Use the following guide to implement structural equality for both reference types and value types.
Equality
The equality check should follow these rules:
xtoyreturns the same truth as comparingytox. (Symmetry)xis equal toyandyis equal toz, thenxmust be equal toz. (Transitivity)null.nullis equal tonull.Let your class or struct implement the
IEquatable<T>interface for custom equality checking,then implement the
IEquatable<T>.Equals(T)andObject.Equals()methods.Equality for reference types (classes)
For reference types, implement the
IEquatable<T>.Equals(T)method like this:Then override
Object.Equals()like this:Equality for value types (structs)
Since value types cannot be
null, implement theIEquatable<T>.Equals(T)method like this:Then override
Object.Equals()like this:Equality operators
For both reference and value types, you may want to override the default equality and inequality operators. Based on this post by Jon Skeet the equality and inequality operators can be implemented like this:
Note that when
leftand/orrightisnull,Object.Equals(object, object)does not call theObject.Equals(object)override (and therefore not theIEquatable<T>.Equals(T)method).Hash code
Sometimes the hash code of an object is important, for example when the object might be put in a dictionary or hash table. In general, when you override the
Equals()method, override theGetHashCode()method. The hash code should follow these rules:So to implement
Object.GetHashCode()for a class or struct that uses structural equality, choose some fields from your object that are immutable and mark themreadonly. Use only those fields to calculate the hash code. Override theObject.GetHashCode()method and implement it like this:Or, if you have only one immutable field, you may consider just using:
If you have no immutable fields, return a constant hash code. For example, the hash code of the type itself.
Structural equality for collections
Collections should not be compared using the default
Equals()method. Instead, the default equality for collections should be reference equality. To also implement structural equality, implement theIStructuralEquatableinterface. For example: