Operator overloading allows us to redefine the functionality of standard operators (such as +
, -
, *
, /
, ==
, !=
, among others) to work with user-defined types.
This allows objects of these types to be manipulated in an intuitive and natural way, similar to primitive types.
To overload an operator in C#, a static method must be defined with the operator
modifier followed by the operator that you want to overload. The method signature must match the operands of the operator.
public static DataType operator Operator(DataType operand1, DataType operand2)
{
// Implementation of custom behavior
}
DataType
: This is the data type for which the operator is being overloaded.Operator
: This is the operator that you want to overload.operand1
,operand2
: These are the operands on which the operator will be applied.
Overloading Arithmetic Operators
It is possible to overload the operators +
, -
, *
, /
. Let’s see this with an example 👇.
Suppose we have a Vector2D
structure that represents a vector in two dimensions. We want to overload the +
operator to add two vectors.
public struct Vector2D
{
public double X { get; }
public double Y { get; }
public Vector2D(double x, double y)
{
X = x;
Y = y;
}
public static Vector2D operator +(Vector2D v1, Vector2D v2)
{
return new Vector2D(v1.X + v2.X, v1.Y + v2.Y);
}
}
In this example,
- The static method
operator +
takes twoVector2D
as parameters - It returns a new
Vector2D
which is the sum of the two vectors
Using the Operator Overloading
Now let’s see how we use our operator overloading. To do this, we instantiate two Vector2D
and apply the +
operator.
Vector2D v1 = new Vector2D(1.0, 2.0);
Vector2D v2 = new Vector2D(3.0, 4.0);
Vector2D result = v1 + v2;
Console.WriteLine($"Result: ({result.X}, {result.Y})");
The output of this code will be:
Result: (4.0, 6.0)
That is, the overloaded +
operator has invoked the static method we defined to apply the sum to our two vectors. While the usage is simple and intuitive.
Overloading Relational Operators
In addition to arithmetic operators, it is also possible to overload relational operators such as ==
and !=
. To do this, we must also overload the Equals
and GetHashCode
methods to maintain consistency.
Let’s see it with an example,
public struct Vector2D
{
public double X { get; }
public double Y { get; }
public Vector2D(double x, double y)
{
X = x;
Y = y;
}
public static bool operator ==(Vector2D v1, Vector2D v2)
{
return v1.X == v2.X && v1.Y == v2.Y;
}
public static bool operator !=(Vector2D v1, Vector2D v2)
{
return !(v1 == v2);
}
public override bool Equals(object obj)
{
if (obj is Vector2D)
{
Vector2D v = (Vector2D)obj;
return X == v.X && Y == v.Y;
}
return false;
}
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
}
Using the Relational Operator Overloading
Once the operators are overloaded, the usage is very simple. Returning to our Vector2D
class, it would look like this,
Vector2D v1 = new Vector2D(1.0, 2.0);
Vector2D v2 = new Vector2D(1.0, 2.0);
Vector2D v3 = new Vector2D(3.0, 4.0);
Console.WriteLine(v1 == v2); // True
Console.WriteLine(v1 != v3); // True