Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Implementing IComparable and IEquatable safely and fully

5.00/5 (1 vote)
22 Jun 2012CPOL2 min read 27K   210  
Using snippets to create a full and correct implementation of complex interfaces

Introduction

Implementing the interfaces IComparable<T> and IEquatable<T> is often not as straightforward as it seems to be at first glance. With this tip I want to give you some help to automate this implementation as far as possible by using snippets in Visual Studio.

Background  

Microsoft defines some guidelines for implementing operators or certain interfaces. The interfaces I had to implement often were IEquatable<T> and IComparable<T>. Experience has taught me that the implementation mostly leads into clerical errors because the correct implementations are relatively complex, moreover the implementations must differ between reference types and value types.  

Here are some remarks that not listed completely but gives you an impression of the matters to consider:  

  • Implementing IEquatable<T> does implicitly require the implementation of the == and != operators (= and <> in VB) 
  • Implementing IComparable<T> does implicitly require the implementation of the non generic IComparable and of the comparison operators <, >, <= and >=.
  • Within the Equal() method you must not use the equality operators - because this would lead into an endless recursion
  • Whitin the operators you must not call Equal() to check whether an argument is null or the query refence-equality - because this will lead into an endless recursion in some circumstances
  • In addition to the Equal() method of the interface the inherited Equal() method as well as the method GetHashCode() must be overridden
  • Within the overridden Equal() method the type of the specified argument must be checked to avoid an invalid cast exception

A complete list of all requirements can be found at the MSDN.

Using the Snippets

The appended file contains some code snippets for C# and Visual Basic that creates the code to implement the interfaces. Unzip the file and copy the snippets into the appropriate directories of your Visual Studio user settings, e.g. "<MyDocuments-folder>\Visual Studio 2010\Code Snippets\<Language>\My Code Snippets". 

Whithin the editor (C# or VB) simply input the shortcut of the snippet you want and press [Tab]. As an example your class may look like this: 

C#
public class MyClass : IEquatable<MyClass>
{
   // ... other code
}

To create the implementation for the interface just input "iequc" (IEquatable for Class) and press [Tab]. 

C#
public class MyClass : IEquatable<MyClass>
{
   // ... other code

   iequc|
}

The result will be as follows:

C#
public class MyClass : IEquatable<MyClass>
{
   // ... other code

   #region IEquatable<MyClass> Member
   
   /// <summary>
   /// Generates a hash code for this object.
   /// </summary>
   /// 
   /// <returns>The hash code of this object.</returns>
   /// 
   /// <remarks>
   /// </remarks>
   /// 
   public override int GetHashCode()
   {
      // TODO: Implement your code here:
      return base.GetHashCode();
   }
   
   /// <summary>
   /// Checks whether this object is equal to the specified one.
   /// </summary>
   /// 
   /// <param name="obj">The object to compare with.</param>
   /// 
   /// <returns><c>true</c> if this object is equal to <paramref name="obj"/>.</returns>
   /// 
   /// <remarks>
   /// This object is equal to <paramref name="obj"/> if <paramref name="obj"/> is not
   /// <c>null</c> and is of the same type as this object and ...
   /// </remarks>
   /// 
   public override bool Equals( object obj )
   {
      return Equals(obj as MyClass);
   }
   
   /// <summary>
   /// Checks whether this object is equal to the specified one.
   /// </summary>
   /// 
   /// <param name="other">The object to compare with.</param>
   /// 
   /// <returns><c>true</c> if this object is equal to <paramref name="other"/>.</returns>
   /// 
   /// <remarks>
   /// This object is equal to <paramref name="other"/> if <paramref name="other"/>
   /// is not <c>null</c> and ...
   /// </remarks>
   /// 
   public bool Equals( MyClass other )
   {
      if( ReferenceEquals(other, null) )
         return false;
   
      if( ReferenceEquals(this, other) )
         return true;
   
      // TODO: Implement your code here:
      throw new NotImplementedException();
   }
   
   /// <summary>
   /// Checks whether the specified objects are equal.
   /// </summary>
   /// 
   /// <param name="left">The object to compare with.</param>
   /// <param name="right">The object to compare.</param>
   /// 
   /// <returns><c>true</c> if <paramref name="left"/> is equal to <paramref name="right"/>.</returns>
   /// 
   /// <remarks>
   /// The two objects are equal if both are <c>null</c> or ...
   /// </remarks>
   /// 
   public static bool operator ==( MyClass left, MyClass right )
   {
      if( ReferenceEquals(left, right) )
         return true;
      
      if( ReferenceEquals(left, null) )
         return false;
      
      return left.Equals(right);
   }
   
   /// <summary>
   /// Checks whether the specified objects are not equal.
   /// </summary>
   /// 
   /// <param name="left">The object to compare with.</param>
   /// <param name="right">The object to compare.</param>
   /// 
   /// <returns><c>true</c> if <paramref name="left"/> is not equal to <paramref name="right"/>.</returns>
   /// 
   /// <remarks>
   /// The two objects are not equal if only one of them is <c>null</c> or ...
   /// </remarks>
   /// 
   public static bool operator !=( MyClass left, MyClass right )
   {
      if( ReferenceEquals(left, right) )
         return false;
      
      if( ReferenceEquals(left, null) )
         return true;
      
      return !left.Equals(right);
   }
	
   #endregion
}

The only line that must be edit is marked with "TODO". The comments should be edited at some parts (marked with "...") to help the clients that will use your class.

All snippets works this way. This means that all each snippet contains exactly one line of code that must be edited. It is always the line that finally does the comparision. All snippets creates the necessary comments that may be adjusted in places.

For beginners: All shortcuts as well as the snippets itself can be modified to fit your own requirements. Just open a snippet within the editor to see how it works. E.g. to modify the shortcut search for the "Shortcut" element and edit its content.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)