# The C# Station Tutorial

######
by Joe Mayo

created 12/18/04, updated 2/22/08, 3/12/08, 4/29/08, 7/6/08, 1/12/09, 9/1/11

## Lesson 18: Overloading Operators

This lesson shows you how to overload C# operators. Our objectives are as follows:

- Understand what operator overloading is
- Determine when it is appropriate to overload an operator
- Learn how to overload an operator
- Familiarize yourself with rules for operator overloading

### About Operator Overloading

In Lesson 2, you learned what operators were available
in C#, which included *+* (plus), *-* (minus), *^* (exclusive
or), and others. Operators are defined for the built-in types, but that's not all.
You can add operators to your own types, allowing them to be used much like the
operators with the built-in C# types.

To understand the need for operator overloading, imagine that you need to perform matrix math operations in your program. You could instantiate a couple 2-dimensional arrays and do what you need. However, add the requirement for the matrix behavior to be reusable. Because you need to do the same thing in other programs and want to take advantage of the fact that you have already written the code, you will want to create a new type.

So, you create a Matrix type, which could be a class or a struct. Now consider how
this Matrix type would be used. You would want to initialize two or more Matrix
instances with data and then do a mathematical operation with them, such as add
or get a dot product. To accomplish the mathematical operation, you could implement
an *Add()*, *DotProduct()*, and other methods to get the job done.
Using the classes would look something like this:

Matrix result = mat1.Add(mat2); // instance

or

Matrix result = Matrix.Add(mat1, mat2); // static

or even worse

Matrix result = mat1.DotProduct(mat2).DotProduct(mat3); // and so on...

The problem with using methods like this is that it is cumbersome, verbose, and
unnatural for the problem you are trying to solve. It would be much easier to have
a *+* operator for the add operation and a *** operator for the dot
product operation. The following shows how the syntax appears using operators:

Matrix result = mat1 + mat2;

or

Matrix result = mat1 * mat2;

or even better

Matrix result = mat1 * mat2 * mat3 * mat4;

This is much more elegant and easier to work with. For a single operation, one could argue that the amount of work to implement one syntax over the other is not that great. However, when chaining multiple mathematical operations, the syntax is much simpler. Additionally, if the primary users of your type are mathematicians and scientists, operators are more intuitive and natural.

### When Not to Use Operator Overloading

A lot of the discussion, so far, has emphasized the need to write code and implement
types in the simplest and most natural way possible. A very important concept to
remember is that although operators are simple, they are not always natural. In
the example above it made sense to use operators with the *Matrix* type.
This is similar to the reason why operators make sense with the built-in types such
as *int* and *float*. However, it is easy to abuse operators and create
convoluted implementations that are hard for anyone, including the original author,
to understand.

For an example of a bad implementation, consider a *Car* class that needs
an implementation allowing you to park the car in a garage. It would be a mistake
to think that the following implementation was smart:

Car mySedan = new Car(); Garage parkingGarage = new Garage();

mySedan = mySedan + parkingGarage; // park car in the garage

This is bad code. If you ever have the temptation to do something like this - don't.
No one will truly understand what it means and they will not think it is clever.
Furthermore, it hurts the maintainability of the application because it is so hard
to understand what the code does. Although the comment is there, it doesn't help
much and if it wasn't there, it would be even more difficult to grasp the concept
of adding a *Car* and a *Garage*.

The idea is this: Use operators where they lend understanding and simplicity to a type. Otherwise, do not use them.

### Implementing an Overloaded Operator

The syntax required to implement an overloaded operator is much the same as a static
method with a couple exceptions. You must use the *operator* keyword and
specify the operator symbol being overloaded. Here's a skeleton example of how the
dot product operator could be implemented:

public static Matrix operator *(Matrix mat1, Matrix mat2) { // dot product implementation }

Notice that the method is static. Use the keyword *operator* after specifying
the return type, *Matrix* in this case. Following the *operator* keyword,
the actual operator symbol is specified and then there is a set of parameters to
be operated on. See Listing 18-1 for a full example of how to implement and use
an overloaded operator.

##### Listing 18-1. Implementing an Overloaded Operator: Matrix.cs

using System; class Matrix { public const int DimSize = 3; private double[,] m_matrix = new double[DimSize, DimSize]; // allow callers to initialize public double this[int x, int y] { get { return m_matrix[x, y]; } set { m_matrix[x, y] = value; } } // let user add matrices public static Matrix operator +(Matrix mat1, Matrix mat2) { Matrix newMatrix = new Matrix(); for (int x=0; x < DimSize; x++) for (int y=0; y < DimSize; y++) newMatrix[x, y] = mat1[x, y] + mat2[x, y]; return newMatrix; } } class MatrixTest { // used in the InitMatrix method. public static Random m_rand = new Random(); // test Matrix static void Main() { Matrix mat1 = new Matrix(); Matrix mat2 = new Matrix(); // init matrices with random values InitMatrix(mat1); InitMatrix(mat2); // print out matrices Console.WriteLine("Matrix 1: "); PrintMatrix(mat1); Console.WriteLine("Matrix 2: "); PrintMatrix(mat2); // perform operation and print out results Matrix mat3 = mat1 + mat2; Console.WriteLine(); Console.WriteLine("Matrix 1 + Matrix 2 = "); PrintMatrix(mat3); Console.ReadLine(); } // initialize matrix with random values public static void InitMatrix(Matrix mat) { for (int x=0; x < Matrix.DimSize; x++) for (int y=0; y < Matrix.DimSize; y++) mat[x, y] = m_rand.NextDouble(); } // print matrix to console public static void PrintMatrix(Matrix mat) { Console.WriteLine(); for (int x=0; x < Matrix.DimSize; x++) { Console.Write("[ "); for (int y=0; y < Matrix.DimSize; y++) { // format the output Console.Write("{0,8:#.000000}", mat[x, y]); if ((y+1 % 2) < 3) Console.Write(", "); } Console.WriteLine(" ]"); } Console.WriteLine(); } }

Similar to the skeleton example of the dot product operator, the Matrix class in Listing 18-1 contains an operator overload for the + operator. For your convenience, I've extracted the pertinent overload implementation in the code below:

// let user add matrices public static Matrix operator +(Matrix mat1, Matrix mat2) { Matrix newMatrix = new Matrix(); for (int x=0; x < DimSize; x++) for (int y=0; y < DimSize; y++) newMatrix[x, y] = mat1[x, y] + mat2[x, y]; return newMatrix; }

The operator is *static*, which is the only way it can and should be declared
because an operator belongs to the type and not a particular instance. There
are just a few rules you have to follow when implementing operator overloads. What
designates this as an operator is the use of the keyword *operator*, followed
by the *+* symbol. The parameter types are both of the enclosing type, *Matrix*.
The implementation of the operator overload creates a new instance of the return
type and performs a matrix add.

### Operator Rules

C# enforces certain rules when you overload operators. One rule is that you must implement the operator overload in the type that will use it. This is sensible because it makes the type self-contained.

Another rule is that you must implement matching operators. For example, if you overload ==, you must also implement !=. The same goes for <= and >=.

When you implement an operator, its compound operator works also. For example, since
the *+* operator for the *Matrix* type was implemented, you can also
use the *+=* operator on *Matrix* types.

### Summary

Operator overloading allows you to implement types that behave like the built-in
types when using operators. Be sure to use operators in a way that is natural and
understandable for the type. Syntax for implementing operators is much like a static
method, but includes the *operator* keyword and the operator symbol in place
of an identifier. Additionally, there are rules, such as maintaining symmetry,for
using operators, which encourage construction of robust types.

I invite you to return for Lesson 19: Encapsulation.