[C# Howto] How to overload the operators?

Operator overloading is a controversial feature. By overloading opeators for your custom classes, you can do some tasks in a simpler and cleaner way.

Somehow, this feature can be overused. For example, you have 2 Product objects. What does “product1 + product2” mean anyway? Operator overloading is a great feature but should be used with caution and only in a situation that everybody will understand the meaning easily.        

 1. Which operator can be overloaded?

  • Binary Operators: Yes
  • Unary Operators: Yes
  • Comparison Operators: Yes
  • Shorthand Assignment Operators ( +=, -=, …)  : Not directly (when you override a binary operator, it’s corresponding assignment operator will work automatically)
  • [] : No, use indexers instead
  • () : No

2. Syntax to overload operators

In C#, a special method is used to overload operators.

  • It should be a “static” method
  • The “operator” keyword is used
  • The number of parameters matches with the number of operands of an operator

3. Overloading Binary Operators

The binary operators (+, -, * …) are very commonly overloaded.

public class Point2D
{
  public int X { get; set; }
  public int Y { get; set; }
  public static Point2D operator +(Point2D p1, Point2D p2)
  {
    return new Point2D { X = p1.X + p2.X, Y = p1.Y + p2.Y };
  }
}

Point2D p1 = new Point2D { X = 1, Y = 2 };
Point2D p2 = new Point2D { X = 3, Y = 4 };
Point2D p3 = p1 + p2;

Console.WriteLine("X = {0}, Y = {1}", p3.X, p3.Y); // 4,6

It is impressively simple. But you do not need to use only the same class type for parameters. For binary operators, the first parameter represents the left side operand and the second parameter is mapped to the right side operand. At least one of the paramters needs to be the target class type.

public static Point2D operator +(Point2D p, int i)
{
  return new Point2D { X = p.X + i, Y = p.Y + i };
}
public static Point2D operator +(int i, Point2D p)
{
  return new Point2D { X = i + p.X, Y = i + p.Y };
}

Point2D p1 = new Point2D { X = 1, Y = 2 };
Point2D p2 = new Point2D { X = 3, Y = 4 };
Point2D p3 = p1 + 3;
Point2D p4 = 3 + p2;

Console.WriteLine("X = {0}, Y = {1}", p3.X, p3.Y);
Console.WriteLine("X = {0}, Y = {1}", p4.X, p4.Y);

Here, you can add an integer to the object and returns a new object.

4. Overloading shorthand assignment operators

It makes sense you can add or substrct an element to/from your collection object.

productList = productList + product;

The good news is that when you overload the binary operator, its corresponding assignment operator is overloaded automatically.

productList += product;

public class Product
{
  public string Name { get; set; }
}

public class ProductList : List<Product>
{
  public static ProductList operator +(ProductList pl, Product p)
  {
    pl.Add(p);
    return pl;
  }
  public static ProductList operator -(ProductList pl, Product p)
  {
    pl.Remove(p);
    return pl;
  }
}

ProductList products = new ProductList();
Product p1 = new Product { Name = "Toy" };
Product p2 = new Product { Name = "Clothes" };
products += p1;
products += p2;
Console.WriteLine("Count: {0}", products.Count); // 2
products -= p1;
Console.WriteLine("Count: {0}", products.Count); // 1

5. Overloading Unary Operators

Overloading an unary operator is very similar with overloading binary operators except:

  • There is only one paramter, whose type is the same as the containing type
public class Point2D
{
  ...

  public static Point2D operator ++(Point2D p)
  {
    return new Point2D { X = p.X + 1, Y = p.Y + 1 };
  }
}

Good! But wait! There are 2 type of the ‘++’ operator; preincrement and postincrement! Which version did I just overload?

Let’s check this out.

First, override the “ToString()” method of the “Point2D” class.

public override string ToString()
{
  return string.Format("X = {0}, Y = {1}", X, Y);
}

Now test the ‘++’ operator.

Point2D p1 = new Point2D { X = 1, Y = 1 };
Console.WriteLine("{0}", ++p1);
p1 = new Point2D { X = 1, Y = 1 }; // reset
Console.WriteLine("{0}", p1++);

The output is, surprisingly,

X = 2, Y = 2
X = 1, Y = 1

You can enjoy the free benefit C# provide for you.

6. Overloading Equality Operators

Operators? Do we have more than one equality operators? Well, there is a counterpart of an “==” operator. That is “!=”

When you overload one of these two, you need to overload the other too. So always override both of them at the same time.

They are binary operators which return a boolean value.

How to implement these methods is up to you. But there is a better pratice you can always follow.

  • Overload “Equals()” and “GetHashcode()” methods
  • Call the “Equals” method in the “==” and “!=” methods
public class Point2D
{
  public int X { get; set; }
  public int Y { get; set; }
  ...
  public override string ToString()
  {
    return string.Format("X = {0}, Y = {1}", X, Y);
  }
  public override bool Equals(object obj)
  {
    return ((obj != null) && (this.ToString() == obj.ToString()));
  }
  public override int GetHashCode()
  {
    return this.ToString().GetHashCode();
  }
  public static bool operator ==(Point2D p1, Point2D p2)
  {
    return p1.Equals(p2);
  }

  public static bool operator !=(Point2D p1, Point2D p2)
  {
    return !p1.Equals(p2);
  }
}

Point2D p1 = new Point2D { X = 1, Y = 1 };
Point2D p2 = new Point2D { X = 1, Y = 1 };
Point2D p3 = new Point2D { X = 2, Y = 3 };
Console.WriteLine(p1 == p2);  // true
Console.WriteLine(p1 != p3);  // true

7. Overloading Comparison Operators

Overloading Comparison Operators is exactly the same as overloading equality operators. Comparison Operators also work as a pair.

  • < and >
  • <= and >=

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s