Conversion Operators






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).

Figure illustrates how you might implement implicit and explicit conversions; detailed analysis follows.

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 Figure, 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



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows