Section 12.4. Conversion Operators


12.4. Conversion Operators

C# will convert (for example) an int to a long implicitly but will only allow you to convert a long to an int explicitly . The conversion from int to long is implicit because you know that any int will fit into the memory representation of a long without losing any information. The reverse operation, from long to int , must be explicit (using a cast) because it is possible to lose information in the conversion:

 int myInt = 5;     long myLong;     myLong = myInt;        // implicit     myInt = (int) myLong;  // explicit 

You want to be able to convert your Fraction objects to intrinsic types (such as int ) and back. Given an int , you can support an implicit conversion to a fraction because any whole value is equal to that value over 1 ( 15 == 15/1 ).

Given a fraction, you might want to provide an explicit conversion back to an integer, understanding that some information might be lost. Thus, you might convert 9/4 to the integer value 2 (truncating to the nearest whole number).

A more sophisticated Fraction class might not truncate, but rather round to the nearest whole number. This idea is left, as they say, as an exercise for the reader, to keep this example simple.


You use the keyword implicit when the conversion is guaranteed to succeed and no information will be lost; otherwise , you use explicit . implicit and explicit are actually operators, often called cast or casting operators because their job is to cast from one type to another ( int to Fraction or Fraction to int ).

Example 12-3 illustrates how you might implement implicit and explicit conversions; detailed analysis follows .

Example 12-3. Conversion operators
 using System; public class Fraction {    private int numerator;    private int denominator;    // create a fraction by passing in the numerator    // and denominator    public Fraction( int numerator, int denominator )    {       this.numerator = numerator;       this.denominator = denominator;    }    // overload the constructor to create a    // fraction from a whole number    public Fraction( int wholeNumber )    {       Console.WriteLine( "In constructor taking a whole number" );       numerator = wholeNumber;       denominator = 1;    }  // convert ints to Fractions implicitly    public static implicit operator Fraction( int theInt )    {       Console.WriteLine( "Implicitly converting int to Fraction" );       return new Fraction( theInt );    }    // convert Fractions to ints explicitly    public static explicit operator int( Fraction theFraction )    {       Console.WriteLine( "Explicitly converting Fraction to int" );       return theFraction.numerator / theFraction.denominator;  }    // overloaded operator + takes two fractions    // and returns their sum    public static Fraction operator +( Fraction lhs, Fraction rhs )    {       // like fractions (shared denominator) can be added       // by adding their numerators       if ( lhs.denominator == rhs.denominator )       {          return new Fraction( lhs.numerator + rhs.numerator,          lhs.denominator );       }       // simplistic solution for unlike fractions       // 1/2 + 3/4 == (1*4) + (3*2) / (2*4) == 10/8       // this method does not reduce.       int firstProduct = lhs.numerator * rhs.denominator;       int secondProduct = rhs.numerator * lhs.denominator;       return new Fraction(       firstProduct + secondProduct,       lhs.denominator * rhs.denominator       );    }    // test whether two Fractions are equal    public static bool operator ==( Fraction lhs, Fraction rhs )    {       if ( lhs.denominator == rhs.denominator &&       lhs.numerator == rhs.numerator )       {          return true;       }       // code here to handle unlike fractions       return false;    }    // delegates to operator ==    public static bool operator !=( Fraction lhs, Fraction rhs )    {       bool equality = lhs == rhs;       return !( equality );    }    // tests for same types, then delegates    public override bool Equals( object o )    {       if ( !( o is Fraction ) )       {          return false;       }       return this == (Fraction)o;    }    // return a string representation of the fraction    public override string ToString(  )    {       String s = numerator.ToString(  ) + "/" +       denominator.ToString(  );       return s;    } } public class Tester {    public void Run(  )    {       Fraction f1 = new Fraction( 3, 4 );       Fraction f2 = new Fraction( 2, 4 );       Fraction f3 = f1 + f2;       Console.WriteLine( "adding f3 + 5..." );       Fraction f4 = f3 + 5;       Console.WriteLine( "f3 + 5 = f4: {0}", f4.ToString(  ) );       Console.WriteLine( "\nAssigning f4 to an int..." );       int truncated = (int)f4;       Console.WriteLine( "When you truncate f4 you get {0}",       truncated );    }    static void Main(  )    {       Tester t = new Tester(  );       t.Run(  );    } } Output: adding f3 + 5... Implicitly converting int to Fraction In constructor taking a whole number f3 + 5 = f4: 25/4 Assigning f4 to an int... Explicitly converting Fraction to int When you truncate f4 you get 6 

In Example 12-3, you add a second constructor that takes a whole number and creates a Fraction :

 public Fraction(int wholeNumber)     {          Console.WriteLine("In constructor taking a whole number");          numerator = wholeNumber;          denominator = 1;     } 

Notice that in this and the following code samples, you add WriteLine( ) statements to indicate when you've entered the method. This is an alternative to stepping through in a debugger. While using the debugger is usually more effective, this kind of output can help you trace the execution of your program for review at a later time.


You want to be able to convert Fractions to and from ints . To do so, create the conversion operators. As discussed previously, converting from a Fraction to an int requires truncating the value, and so must be explicit :

 public static  explicit  operator int(Fraction theFraction)     {          Console.WriteLine("Explicitly converting Fraction to int");          return theFraction.numerator /          theFraction.denominator;     } 

Note the use of the explicit keyword, indicating that this requires an explicit cast from a Fraction to an int. You see the cast in the Run( ) method:

 int truncated = (int) f4; 

The cast from an int to a Fraction , on the other hand, is perfectly safe, so it can be implicit:

 Fraction f4 = f3 + 5; 

Notice that there is no explicit cast (in parentheses). When you add the int to the Fraction , the int is implicitly cast to a Fraction . The implementation of this is to create a new Fraction object and to return it:

 public static  implicit  operator Fraction(int theInt)     {          Console.WriteLine("Implicitly converting int to Fraction");          return  new Fraction(theInt)  ;     } 

Calling the implicit cast operator causes the constructor to be invoked:

 public Fraction(int wholeNumber)     {          Console.WriteLine("In constructor taking a whole number");          numerator = wholeNumber;          denominator = 1;     } 

You see this sequence of events represented in the output:

 Implicitly converting int to Fraction     In constructor taking a whole number 



Learning C# 2005
Learning C# 2005: Get Started with C# 2.0 and .NET Programming (2nd Edition)
ISBN: 0596102097
EAN: 2147483647
Year: 2004
Pages: 250

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net