Team LiB
Previous Section Next Section

Using C# Operators

C# provides several operators for arithmetic, logical, increment, decrement, and other operations. C# also provides for shorthand notations for common situations such as adding an amount to a variable. In addition, most of the C# operators can be overloaded by the developer. Overloading enables the developer to specify the behavior for the operator when applied to a specific type. Overloading will be covered later in this chapter. Table 3.1 provides a listing of all operators for C#.

Table 3.1. C# Operators

Category

Operator

Description

Can Overload?

Arithmetic

+

Addition

Yes

 

-

Subtraction

Yes

 

*

Multiplication

Yes

 

/

Division

Yes

 

%

Modulus remainder

Yes

Logical

&

Bitwise AND

Yes

 

|

Bitwise OR

Yes

 

^

Bitwise exclusive OR

Yes

 

!

Logical negation

Yes

 

~

Bitwise complement

Yes

 

&&

Logical AND

Not directly

 

||

Logical OR

Not directly

Increment/decrement

++

Pre/post increment

Yes

 

--

Pre/post decrement

Yes

Shift

<<

Binary left shift

Yes

 

>>

Binary right shift

Yes

Relational

==

Equality

Yes

 

!=

Not equal

Yes

 

<

Less than

Yes

 

>

Greater than

Yes

 

<=

Less than or equal

Yes

 

>=

Greater than or equal

Yes

Assignment

=

Assign

No

 

+=

Add assign

Not directly

 

-=

Subtract assign

Not directly

 

*=

Multiply assign

Not directly

 

/=

Divide assign

Not directly

 

%=

Modulus assign

Not directly

 

&=

Bitwise AND assign

Not directly

 

|=

Bitwise OR assign

Not directly

 

<<=

Left-shift assign

Not directly

 

>>=

Right-shift assign

Not directly

Member access

.

Member access

No

Indexing

[]

Indexing

No, but indexers can be defined

Cast

()

Casting

No, but cast operators can be defined

Conditional

?:

Ternary if statement

No

Object creation

new

Creates an instance of an object

No

Type information

as

Safe cast to specified type

No

 

is

Used to determine whether a type is of a specified type

No

Overflow

checked

Controls overflow checking context

No

 

unchecked

Controls overflow checking context

No

Indirection and address

*

Pointer dereference

No

 

->

Pointer member access

No

 

[]

Pointer indexing

No

 

&

Address of

No


It's important to note the operators for which overloading cannot be performed directly. This category of operators is really shorthand notations for an extended syntax. For example, the expression x += y gets expanded and evaluated as x = x + y; therefore, if the addition operator + is overloaded, that operator will be used in the evaluation of the += operator. Operator overloading is a powerful feature of C# that offers the flexibility to allow for user-defined types to be manipulated as if they were built-in C# types. To explore the power of C# operators, create a new C# console application and name it Operators. Then copy the code from Listing 3.2 into the project. Build and run the project without debugging (Ctrl+F5) to see the output.

Listing 3.2. C# Operator Overloading in Action
   ////////////////////////////////////////////////////
   ///This project demonstrates operator overloading
   ///in C#
   ////////////////////////////////////////////////////
   using System;

   namespace Operators {


       /// <summary>
       /// Mile class will define operators for increment/decrement
       /// </summary>
       public class Mile {

           private int        m_wholePart    = 0;
           private int        m_tenthPart    = 0;

           public int WholePart { get { return m_wholePart; } set { m_wholePart = value; } }
           public int Tenths    { get { return m_tenthPart; } set { m_tenthPart = value; } }

           public Mile( ) { }


           //operators


           /// <summary>
           /// Increment the tenths of a mile
           /// </summary>
           static public Mile operator++( Mile mile ) {
               mile.m_tenthPart++;
               if( mile.m_tenthPart >= 10 ) {
                    mile.m_wholePart++;
                    mile.m_tenthPart -= 10;
                }
                return mile;
           }

           /// <summary>
           /// Decrement the number of tenths in the mile
           /// </summary>
           static public Mile operator--( Mile mile ) {
               mile.m_tenthPart--;
               if( mile.m_tenthPart < 0 ) {
                   mile.m_wholePart--;
                   mile.m_tenthPart = 10 + mile.m_tenthPart;
               }
               return mile;
           }

           /// <summary>
           /// Add two mile objects together
           /// </summary>
           static public Mile operator+( Mile a, Mile b ) {
               int tenthPart    = a.m_tenthPart + b.m_tenthPart;
               int wholePart = a.m_wholePart + b.m_wholePart;
               if( tenthPart >= 10 ) {
                   tenthPart = tenthPart - 10;
                   wholePart++;
               }
               Mile result = new Mile( );
               result.m_tenthPart    = tenthPart;
               result.m_wholePart    = wholePart;
               return result;
           }

           /// <summary>
           /// Subtract two different Mile objects
           /// </summary>
           static public Mile operator-( Mile a, Mile b ) {
               Mile result = new Mile( );
               result.m_tenthPart    = a.m_tenthPart - b.m_tenthPart;
             if( result.Tenths < 0 ) {
                  result.m_tenthPart                = 10 - result.m_tenthPart;
                  result.m_wholePart                = a.m_wholePart - b.m_wholePart - 1;
                } else {
                    result.m_wholePart                = a.m_wholePart - b.m_wholePart;
                }
                return result;
          }

           /// <summary>
           /// Returns the number of feet in a mile when casted to an float value
           /// </summary>
           static public explicit operator float( Mile mile ) {
               float feet = 5280 * mile.m_wholePart;
               feet *= ( (float)mile.m_tenthPart / 10.0f );
               return feet;
           }

           /// <summary>
           /// override the ToString method and return WholePart.TenthPart
           /// </summary>
           public override string ToString() {
               return string.Format( "{0}.{1}", m_wholePart, m_tenthPart );
           }

       }


       /// <summary>
       /// Test harness for operators
       /// </summary>
       class OperatorTest {

           /// <summary>
           /// Defines the entry point for the application
           /// </summary>
           static void Main( ) {
               Mile mile = new Mile( );

               mile.WholePart    = 5;           //5 miles
               mile.Tenths       = 1;           //5.1 miles

               mile++;                         //5.2 miles 
               Console.WriteLine( mile );      //the ToString //method will be invoked on
 the Mile class
               mile++;                         //5.3 miles
               Console.WriteLine( mile );

               float feet    = (float)mile;    //get the //number of feet in 5.3 miles

               //Display the number of feet in 5.3 miles
               Console.WriteLine( "Number of feet in {0} miles is {1}", mile, feet );


               Mile mile2    = new Mile( );
               mile2.WholePart    = 2;

               Mile result = mile - mile2;        //result should equal 3.3 miles
               Console.WriteLine( "{0} - {1} = {2}", mile, mile2, result );
           }
       }
   }

Listing 3.2 begins by defining a class called Mile. The Mile class keeps track of whole miles and tenths of a mile. By overloading various operators such as increment, decrement, and addition, and a casting operator, the Mile class acts as if it were a built-in C# type. Walking through the code with the debugger will help to gain an insight as to what is happening during the execution of the code. Place a breakpoint on the shaded line at line 114 of Listing 3.2. This is the first place where one of the overloaded operators will be invoked. It's important to realize that operators are just syntactic sugar for method calls. The literal translation of line 114 is mile = Mile.operator++( mile ). For now, ignore everything in the listing expect for the operator-overloading code . The rest, such as the properties WholePart and Tenths, and the fields m_wholePart and m_tenths, will be covered in Chapter 6, "Objects and Classes." Right now, just focus on the operators. From line 114, the code executes the overloaded increment operator found on line 29. From there, the m_tenths value is incremented with the same ++ operator that is defined for integer types.

    Team LiB
    Previous Section Next Section