BlackWaspTM
C# Programming
.NET 1.1+

C# Relational Operator Overloading

The eleventh article in the C# Object-Oriented Programming tutorial furthers the investigation of operator overloading. This time the overloading of the relational operators is described, allowing custom classes to be included in comparison operations.

The Relational Operators

The relational operators allow two values or objects to be compared and a determination made as to whether they are equal or whether one is greater or smaller than the other. There are six relational operators that can be directly overloaded for a class. These are the equality (==) and inequality (!=) operators, greater than (>), less than (<), greater than or equal to (>=) and less than or equal to (<=).

The six operators should be considered as three linked pairs. When one of any of the three pairs is overloaded, the opposing version must also be overloaded to enable the class to be compiled without error.

This article uses the Vector class developed over previous articles. The Vector class represents a two-dimensional vector and already overloads arithmetic operators, true and false operators and logical operators. If you do not have the code, download it using the link above.

Overloading the Equality and Inequality Operators

Syntax

The equality and inequality operators are binary operators and, as such, are overridden using the same syntax as other basic binary operators. The following syntax is for the equality operator:

public static result-type operator ==(
    op-type operand,
    op-type2 operand2
)

The result-type is the data type for the return value of the operation. In most cases the result will be a Boolean value. A different return type may be used but this will limit the operator's functionality. At least one of the two operands must be of the same data type as the containing class. By changing the data type of one of the operands, multiple overloaded versions of the operator can be created and used for comparing objects of different types.

Functional Impact

Overloading the equality operator fundamentally changes the manner in which objects are compared. Under normal circumstances, a comparison of two objects using the equality operator yields a true result only if the two variables being compared are references to the same object. ie. The two object references point to the same area in memory. This can be demonstrated using instances of the Vector class and the VectorDemo project's Main method as shown in the following example. Note that though vectors v1 and v2 are the same in value, they are not deemed equal.

static void Main(string[] args)
{
    Vector v1 = new Vector(3, 4);
    Vector v2 = new Vector(3, 4);
    Vector v3 = v2;

    Console.WriteLine(v2 == v1);                // Outputs "False"
    Console.WriteLine(v3 == v2);                // Outputs "True"
}

When you overload the equality operator you can change the comparison from being a direct test that the two object references are the same to being a test that the objects are functionally the same in value. This concept is used by the .NET framework's provision of string objects. For strings, the equality operator is overloaded so that a comparison of the two strings' values, rather than their object pointers, is made.

Overloading Equality and Inequality Operators in the Vector Class

Using the syntax described above we can add overloaded equality and inequality operators to the Vector class. The operations will check that both the X and Y co-ordinates of the two Vectors being compared match before deeming the objects to be equal. To overload the two operators, add the following code to the Vector class:

public static bool operator ==(Vector v1, Vector v2)
{
    return (v1.X == v2.X && v1.Y == v2.Y);
}

public static bool operator !=(Vector v1, Vector v2)
{
    return (v1.X != v2.X || v1.Y != v2.Y);
}

These modifications change the comparisons so that the previous Main method's results are different. Execute the program again to see that the equality operator now compares the values in the Vector rather than the object references. Note that the v1 and v2 vectors are now considered equal.

static void Main(string[] args)
{
    Vector v1 = new Vector(3, 4);
    Vector v2 = new Vector(3, 4);
    Vector v3 = v2;

    Console.WriteLine(v2 == v1);                // Outputs "True"
    Console.WriteLine(v3 == v2);                // Outputs "True"
}

The Equals Method

Every class automatically inherits the Equals method. This method performs a comparison of two values or objects, returning a Boolean value indicating if the two items match. For reference type objects such as the Vector class, the comparison is of the two object references. Once the equality operator has been overloaded, the results of == and the Equals method are no longer the same:

static void Main(string[] args)
{
    Vector v1 = new Vector(3, 4);
    Vector v2 = new Vector(3, 4);
    Vector v3 = v2;

    Console.WriteLine(v2 == v1);                // Outputs "True"
    Console.WriteLine(v3 == v2);                // Outputs "True"
    Console.WriteLine(v2.Equals(v1));           // Outputs "False"
    Console.WriteLine(v3.Equals(v2));           // Outputs "True"
}

Generally you will want to modify the functionality of the Equals method to match that of the equality operator. This is achieved by overriding the method; a technique that will be described in a later article in this tutorial. After changing the Equals method, a test that the references for two objects match can still be made using the static ReferenceEquals method.

9 December 2007