IComparable
Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio
Contents |
The System.IComparable interface defines a generalized comparison method to be implemented by a value type or class. It is used to create a type-specific method for comparing and ordering instances.
Generic version (preferred)
Syntax
Declaration syntax
public interface IComparable<T>
The IComparable interface defines the CompareTo method:
Method syntax
int CompareTo (T comparee)
where comparee is an object to be compared with this object.
| Return value | Meaning |
| Less than zero (< 0) | Comparer < Comparee
|
| Zero (0) | Comparer = Comparee
|
| Greater than zero (> 0) | Comparer > Comparee
|
Usage
Simple equality (==) example
class Vector { private double m_X, double m_Y, double m_Z; public Vector(double x, double y, double z) { m_X = x; m_Y = y; m_Z = z; } public double getX() { return m_X; } public double getY() { return m_Y; } public double getZ() { return m_Z; } }
Vector myVA = new Vector(1.5, 1.5, 1.5); Vector myVB = new Vector(1.5, 1.5, 1.5); if (myVA == myVB) { Console.WriteLine("myVA = myVB"); } else { Console.WriteLine("myVA != myVB"); }Output:
myVA != myVB
The reason for this result is that the == compares the value stored in the variables myVA and myVB. Because these represent instances of classes, they are reference types; so, the values are memory addresses where the actual objects are stored on the heap. Therefore, they can never be identical unless they actually point to the same object as follows:
Vector myVA = new Vector(1.5, 1.5, 1.5); Vector myVB = myVA; if (myVA == myVB) { Console.WriteLine("myVA = myVB"); } else { Console.WriteLine("myVA != myVB"); }Output:
myVA = myVB
CompareTo()
When implementing IComparable you a must create a CompareTo(Comparee) method which returns an int indicating three main states:
| Return value | Meaning |
| Less than zero (< 0) | Comparer < Comparee
|
| Zero (0) | Comparer = Comparee
|
| Greater than zero (> 0) | Comparer > Comparee
|
This means you must give some thought to what you actually want to compare of the class.
With the Vector class the most likely attribute to compare is the magnitude. With this in mind the Vector class now becomes:
class Vector : IComparable<Vector> { private double m_Xm double m_Y, double m_Z; public Vector(double x, double y, double z) { m_X = x; m_Y = y; m_Z = z; } public double getX() { return m_X; } public double getY() { return m_Y; } public double getZ() { return m_Z; } #region IComparable<Vector> Members public int CompareTo(Vector other) { Double magnitudeThis = 0; Double magnitudeThat = 0; int returnValue = 0; magnitudeThis += Math.Pow(m_X, 2); magnitudeThis += Math.Pow(m_Y, 2); magnitudeThis += Math.Pow(m_Z, 2); magnitudeThat += Math.Pow(other.getX(), 2); magnitudeThat += Math.Pow(other.getY(), 2); magnitudeThat += Math.Pow(other.getZ(), 2); magnitudeThis = Math.Sqrt(magnitudeThis); magnitudeThat = Math.Sqrt(magnitudeThat); //In practice catch the exception! returnValue = Convert.ToInt32((magnitudeThis - magnitudeThat)); return returnValue; } #endregion }
Vector myVA = new Vector(1.5, 1.5, 1.5); Vector myVB = new Vector(1.5, 1.5, 1.5); if (myVA.CompareTo(myVB) == 0) { Console.WriteLine("myVA = myVB"); } else { Console.WriteLine("myVA != myVB"); }Output:
myVA = myVB
Non-generic version (backward compatible)
Syntax
Declaration syntax
[ComVisibleAttribute(true)] public interface IComparable
Method syntax
The IComparable interface defines the CompareTo method:
int CompareTo (Object comparee)
where comparee is an object to be compared with this object.
Non-Generic type checking
If you do not use the generic IComparable, then you must type check the comparee object and either cast it within the CompareTo method or throw an exception if it is not comparable. This means that possible errors will now only be caught at runtime instead of compile time.
Note: The example now has extra code as it has to check for this exception and, also, have to cast the object each time.
class Vector : IComparable { private double m_X, double m_Y, double m_Z; public Vector(double x, double y, double z) { m_X = x; m_Y = y; m_Z = z; } public double getX() { return m_X; } public double getY() { return m_Y; } public double getZ() { return m_Z; } #region IComparable Members public int CompareTo(object obj) { if (obj is Vector) { Vector that = (Vector) obj; Double magnitudeThis = 0; Double magnitudeThat = 0; int returnValue = 0; magnitudeThis += Math.Pow(m_X, 2); magnitudeThis += Math.Pow(m_Y, 2); magnitudeThis += Math.Pow(m_Z, 2); magnitudeThat += Math.Pow(that.getX(), 2); magnitudeThat += Math.Pow(that.getY(), 2); magnitudeThat += Math.Pow(that.getZ(), 2); magnitudeThis = Math.Sqrt(magnitudeThis); magnitudeThat = Math.Sqrt(magnitudeThat); //In practice catch the exception! returnValue = Convert.ToInt32((magnitudeThis - magnitudeThat)); return returnValue; } throw new ArgumentException("Object cannot be compared"); } #endregion }