Overload C# Operators

Extend and customize C# to make your apps easier to read and maintain.

Mike Amundsen

October 30, 2009

11 Min Read
ITPro Today logo in a gray background | ITPro Today

SharpShooter

Languages: C#

Technologies: Overloading| Operator Overloading

 

OverloadC# Operators

Extendand customize C# to make your apps easier to read and maintain.

 

By MikeAmundsen

 

C# hasmany great features that make it a powerful and fun language. One of thosefeatures is the ability to redefine the functionality and meaning of one ormore methods, including the language's built-in methods. This is calledoverloading. The ability to overload methods in C# gives you the power todesign systems that have their own self-consistent syntax and logic.Overloading also allows you to extend the language in ways that were notinitially conceived by the folks who implemented the C# language on the .NETplatform. In short, overloading is a valuable tool for extending andcustomizing the C# language for your own needs.

 

You canapply overloading to many situations. In this article, I'll focus on how C#enables you to overload reserved keywords in the language, such as the logicaloperators (==, !=, <, and >) and thearithmetic operators (+, -, *, /, %). You'lllearn how you can redefine the meaning and behavior of these key languageoperators to help make your own programs more self-consistent and easier toread and maintain over time.

 

A Simple Overloading Example: ToString

Beforegetting into the details of overloading relational and arithmetic operators, itwould be good to start with a simple overloading example: overloading the ToStringmethod. The ToString method is a base-class method inherited by all typesand classes defined in C#. It's the method used to come up with a stringrepresentation of the type or class with which you are working.

 

Forexample, this code uses the built-in ToString method to output the valueof an integer:

 

Int x = 13;

System.Console.WriteLine(x.ToString());

 

Becauseall classes and types inherit this method, it's easy for you to call it on anyclass or type you create. However, if you have created a custom type notpreviously defined in C#, the ToString method may not know how to outputthe string properly. FIGURE 1 shows a simple custom type named Point,which holds two values, x and y.

 

// compile string:

// csc /t:library/out:Amundsen.SharpShooter.Overloading.Point.dllAmundsen.SharpShooter.Overloading.Point.cs

 

using System;

 

namespace Amundsen.SharpShooter.Overloading {

 

    public class Point {

 

        private int x;

        private int y;

 

        public Point(intx, int y) {

            this.x=x;

            this.y=y;

        }

 

        public overridestring ToString() {

            return(String.Format("x={0}, y={1}",x,y));

        }

    }

}

FIGURE 1:This code creates a custom type that overloads the ToString method.

 

You'llnotice that there is an overload for the ToString method defined in thisclass. This new version of ToString will print both the x and y valuesof the Point object. This overload for ToString basically tellsthe run time how to behave when a program asks for the string representation ofthe custom Point object.

 

FIGURE 2shows an aspx page that uses the compiled assembly from FIGURE 1 to create the Pointtype and uses the ToString method to produce a string representation ofthe Point object.

 

<%@ page description="overloading ToString" %>

<%@ importnamespace="Amundsen.SharpShooter.Overloading" %>

 

  void submit_click(object sender, EventArgs args) {      int x =Int32.Parse(PointX.Text);     int y =Int32.Parse(PointY.Text);       Point p = newPoint(x,y);     output.Text=p.ToString();} 

 

Overloading ToString()

 

x:

y:

    Text="Submit"     id="submit"     onclick="submit_click"     runat="server"/>

 

ToString:

 

FIGURE2: This aspx pageuses the Point object and the overloaded ToString method.

 

FIGURE 3 shows the resulting page in a Web browser.

 


FIGURE 3: Executing the ToString method of thePoint object results in this page.

 

Now thatyou know how to use overloading to modify the behavior of the built-in ToStringmethod, it's time to learn how to overload relational operators for a customtype or class.

 

Overloading Relational Operators

Althoughoverloading the ToString method for custom types is a common task, thereare other overloading-related issues you must consider when creating a customtype or class. For example, you might want to alter the default behavior whencomparing two values. This is especially handy when you want to create sortingrules for custom objects. It's relatively simple to sort scalar values such asstrings and numbers, but it's not at all clear how you might want objects to besorted in a list (such as by ID, by name, or by some combination ofproperties). For this reason, you might want to overload the ==, !=, <,and > operators for your custom type.

 

Forexample, the code in FIGURE 4 creates a Person class with ID and Nameproperties. Compile this assembly and place it in a bin folder of your Web.

 

using System;

 

namespace Amundsen.SharpShooter.Overloading {

    public class Person {

        private string_name;

        private int _id;

 

        public Person(intid, string name) {

            _id = id;

             _name = name;

        }

 

        public string Name{

            get {

                return_name;

            }

            set {

                _name=value;

            }

        }

 

        public int ID {

            get {

                return _id;

            }

            set {

                _id =value;

            }

        }

 

        public overridestring ToString() {

            return(_name+" ("+_id.ToString() +")");

        }

    }

}

FIGURE 4: Thecustom Person class has ID and Name properties for comparison checking.

 

Theperson.aspx page shown in FIGURE 5 uses the Person assembly to createtwo objects with the same ID and Name values to illustrate theresults of the equality comparison check.

 

<%@ page description="overloading logical operators"%>

<%@ importnamespace="Amundsen.SharpShooter.Overloading" %>

 

  void submit_click(object sender, EventArgs args) {       int idA = Int32.Parse(PersonA_ID.Text);     string nameA = PersonA_Name.Text;     Person pa = newPerson(idA,nameA);       int idB =Int32.Parse(PersonB_ID.Text);     string nameB =PersonB_Name.Text;     Person pb = newPerson(idB,nameB);       output.Text="
"+         pa.ToString()+"
"+         pb.ToString()+"
"+          (pa==pb).ToString();} 

 

 

Overloading Relational Operators

 

Person A:

ID:


Name:


Person B:

ID:


Name:


 

    Text="Submit"     id="submit"     onclick="submit_click"     runat="server"/>

 

ToString:

 

FIGURE5: This aspx pagereturns False - that is, non-equality - when asked to compare two identicalpersons.

 

When yourun this page, enter identical values for ID and Name for bothobjects, and press submit, you'll see that the comparisonreturns False. You might think that two objects with the same IDand Name settings would be equal, but they are not. That is because thebuilt-in Equals method of the base type compares object locations, notcontents. If you wanted these two objects to report True when doing anequality test, you need to overload the Equals method as well as the ==and != operators.

 

Operatoroverloading is relatively simple, and there are only a few rules to keep inmind. First, if you overload the == operator, you also have to overloadthe != operator. The same is true for the < and >operators. They must be overloaded in pairs in order to maintain consistency.Also, when overloading equality for objects, you need to overload the GetHashCodebuilt-in method. The run time uses the GetHashCode method to support thecomparison check, and failure to overload it can produce errors or unwantedresults.

 

FIGURE 6shows the same Person class with the Equals method, GetHashCodemethod, and the == and != operators overloaded properly.

 

using System;

 

namespace Amundsen.SharpShooter.Overloading {

  public class Person {

    private string _name;

    private int _id;

 

    public Person(int id,string name) {

        _id = id;

        _name = name;

    }

 

    public string Name {

        get {

            return _name;

        }

        set {

            _name=value;

        }

    }

 

    public int ID {

        get {

            return _id;

        }

        set {

            _id = value;

        }

    }

 

    public override stringToString() {

        return(_name+" ("+_id.ToString() +")");

    }

 

    public override boolEquals(object obj) {

        Person p2 =(Person)obj;

        if (_id != p2.ID){

            return(false);

        }

         if (_name != p2.Name) {

            return(false);

        }

        return(true);

    }

 

    public static booloperator == (Person p1, Person p2) {

        return(p1.Equals(p2));

    }

 

    public static booloperator != (Person p1, Person p2) {

         return(p1.Equals(p2));

    }

 

    public override intGetHashCode() {

        return(_id);

    }

  }

}

FIGURE 6:Adding overloads for Equals, GetHashCode, and the == and != operators.

 

Afterre-compiling the same Person class from FIGURE 6, you can retest theaspx page from FIGURE 5, and you'll see that the two objects now report thatthey are equal (see FIGURE 7 for the browser output).

 


FIGURE 7: Testing the Person.aspx page withrelational overloading.

 

Overloading Arithmetic Operators

Alongwith the ability to overload the built-in methods of ToString, GetHashCode,Equals, and the relational operators, you also can overload thearithmetic operators, such as +, -, *, and /. Althoughthis is not a common requirement, there are times when it might come in handy.For example, if you want to create a data type that uses an arithmetic baseother than the common base 10, you need to change the behavior of all thearithmetic operators.

 

Considerthis: You need to create a class that supports base-five arithmetic. For thosenot familiar with arithmetic operations on a non-standard base, the base-fivecounting method looks like this: 0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20.

 

Theones' place in a base-five system can contain a 0,1,2,3, or 4. However, if youadd one more unit to the value of 4, it is represented as 10. That is becausein a base-five system, you must place a 1 in the fives' place and a 0 in theones' place.

 

FIGURE 8shows the code for a C# struct named obn (for odd base numeral) thatdoes just what we need. It allows users to initialize an instance of the typeusing an integer value and then performs basic math operations using base-fiveinstead of base-10.

 

namespace Amundsen.SharpShooter.Overloading {

 

    // odd base numeralstructure

    public struct obn {

 

        int value;

        int baseValue;

     

        // constructorsets base and accepts integer

        public obn(intvalue) {

            baseValue=5;

            this.value =value;

        }

 

        // always returnsvalue in the local baseValue

        public overridestring ToString() {

            return(convertToObn(value).ToString());

        }

 

        // overload theadd operator

        public static obnoperator +(obn v1, obn v2) {

            return(newobn(v1.value+v2.value));

        }

 

        // overload thesubtract operator

        public static obnoperator -(obn v1, obn v2) {

            return(newobn(v1.value-v2.value));

        }

 

        // overload themultiply operator

        public static obnoperator *(obn v1, obn v2) {

            return(newobn(v1.value*v2.value));

        }

 

        // overload thedivide operator

        public static obnoperator /(obn v1,obn v2) {

            return(newobn(v1.value/v2.value));

        }

 

        // overload theremainder operator

        public static obnoperator %(obn v1, obn v2) {

            return(newobn(v1.value%v2.value));

        }

        // overload theincrement operator

        public static obnoperator ++(obn v1) {

            return(newobn(v1.value+1));

        }

 

        // overload thedecrement operator

        public static obnoperator --(obn v1) {

            return(newobn(v1.value-1));

        }

 

        // overload thenegation operator

        public static obnoperator -(obn v1) {

             return(new obn(-v1.value));

        }

 

        // method toconvert to the custom baseValue

        private intconvertToObn(int val) {

            inttensValue=(int)val/baseValue;

            intonesValue=(int)val%baseValue;

            int obnValue=(int)(tensValue*10)+onesValue;

            returnobnValue;

        }

    }

}

FIGURE 8:Creating a custom type that supports non-standard base arithmetic.

 

Inscanning the code in FIGURE 8, you'll notice quite a few operator overloadshave been implemented. Not only the basic addition (+), subtraction (-),multiplication (*), and division (/), but also the remainder (%),unary negation (-), increment (++), and decrement (--) operatorshave been overloaded. You'll also notice the ToString method has beenoverloaded to call the private convertToObn method that does the realwork of converting the integer values to their representations in your custombase-five system.

 

Aftercompiling this custom class and placing it in the bin folder of a Web, you canuse the OddBase.aspx page shown in FIGURE 9 to test the base-five arithmetic.

 

<%@ page description="overloading arithmeticoperators" %>

<%@ importnamespace="Amundsen.SharpShooter.Overloading" %>

 

  void submit_click(object sender, EventArgs args) {      int v1 =Int32.Parse(value1.Text);     int v2 =Int32.Parse(value2.Text);       obn o1 = new obn(v1);     obn o2 = new obn(v2);       output.Text =         String.Format("addition.........:          {0}+{1}={2}",o1,o2,o1+o2)+"
"+         String.Format("subtraction.....:          {0}-{1}={2}",o1,o2,o1-o2)+"
"+         String.Format("multiplication...:          {0}*{1}={2}",o1,o2,o1*o2)+"
"+         String.Format("division.........:          {0}/{1}={2}",o1,o2,o1/o2)+"
"+         String.Format("remainder........:          {0}%{1}={2}",o1,o2,o1%o2)+"
"+         String.Format("increment........:          {0},++{1}",o2,++o2)+"
"+         String.Format("decrement........:          {0},--{1}",o2,--o2)+"
"+          String.Format("negation.........:          {0},{1}",o1,-o1)+"
";   } 

 

Overloading Arithmetic Operators

 

Value1:


Value2:


    id="submit"     text="Submit"     onclick="submit_click"     runat="server"/>

 

Results in base 5:

 

FIGURE9: Creating anaspx page to test the arithmetic-overloaded custom type.

 

The aspxpage accepts two integer values and then performs a series of arithmeticoperations on those numbers using the custom type. FIGURE 10 shows the resultsin a browser when you enter the integer values 13 and 9.

 


FIGURE 10: Testing the aspx page thatperforms base-five arithmetic.

 

The files referenced in thisarticle are available for download.

 

Mike Amundsen is president, chief cook, and bottle washer atEraServer.NET, a .NET hosting and XML Web Services company. He also heads aconsulting firm, Amundsen.com Inc., which enables clients to design, code,implement, and maintain successful .NET solutions efficiently. A well-knownauthor and lecturer, Mike continues to travel the world teaching and speakingon .NET development issues. His latest book, with Paul Litwin, is ASP.NET for Developersfrom SAMS. He is also working on the fourth edition of Teach Yourself Database Programming withVisual Basic .NET in 21 Days and has more than a dozen other book titlesto his credit. When he's not in the server room or on the road, Mike spendstime with his family in and around their home in Northern Kentucky. Readers maycontact Mike at mailto:[email protected].

 

Tell us what you think! Please send any comments about thisarticle to [email protected] include the article title and author.

 

 

 

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like