Pages

Sunday, July 11, 2010

Operator Overloading with Implicit and Explicit Casts in C#

Its been a very common mistake of not declaring implicit and explicit cast operator overloads while working with data types which might take part in some calculations in long run. I found many of the developers don't know why we use checked or unchecked while doing calculations. On this regard, I thought to post an article on how you can use Cast overloads to get your job done easily when you require your type to take part in arithmetic operations and casts to arithmetic data types.

Let us explain the concept using an example. Say I declare a class that would take Feet and inches in one single type. C# doesn't expose such type to us. So let us create one for us to demonstrate the concept.


public class Finch
    {
        private int feet;
        private int inch;

        public int Feet
        {
            get { return this.feet; }
            set
            {
                this.feet = value;
            }
        }
        public int Inches
        {
            get { return this.inch; }
            set
            {
                if (value > 11)
                {
                    this.feet += (value / 12);
                    this.inch = (value % 12);
                }
                else
                    this.inch = value;
            }
        }
        public override string ToString()
        {
            return string.Format("{0}''{1}'", this.Feet, this.Inches);
        }
    }

So you can see I have declared a class Finch which has two members Feet and Inches. The class is used to hold. As a matter of fact, the value of inches cannot be made over 11. So in the setter of inches, we strip the values which is greater than 11 to add up to the feet. So that we always get the proper value for Feets and inches.

Lets take the class a bit further.
Download Source Code - 30KB



Operator Overloading

We all might somehow know what operator overloading is. Overloading an operator means extending the nature of a normal operator to make it work little more of what it is capable of doing so. Lets overload the operator + for our class Finch.

public static Finch operator +(Finch oldvalue, dynamic value)
{
    checked
    {
        if (value is Finch)
        {
            Finch newValue = value as Finch;
            oldvalue.Feet += newValue.Feet;
            oldvalue.Inches += newValue.Inches;
            return oldvalue;
        }
        else //try if its a fraction
        {
            decimal d;
            try
            {
                d = Convert.ToDecimal(value); // when convertion fails it throws exception in runtime
            }
            catch
            {
                throw;
            }
            oldvalue.Feet += Convert.ToInt32(Decimal.Truncate(d));
            var thisval =  Math.Abs(oldvalue.feet - d);
            oldvalue.Inches += (int)(.83f / Convert.ToSingle(thisval));
            return oldvalue;
        }
    }
}
In the above code you can see we have overloaded the + operator to take almost everything in compile type, as we defer the check to  run time using dynamic keyword. If you are not aware of this, please take a look at my previous article, to clear it up. If you are not in C# 4.0, you can easily replace it to any of the known data types.

You can see I have wrapped the entire code within a checked block. This will ensure that the block throws OverflowException whenever the conversion produces Arithmetic Overflows. If you dont want this to happen, you can either wrap the checked block into a try-Catch block to ensure you handle the OverflowException within it.

As we overload the + operator with dynamic variable, we first check whether the dynamic variable is an object of Finch. If so, we just add up the feet and inches of the new Finch variable.
Otherwise we check if the value is convertible to a Decimal. This will also ensure that the variable passed within the block can take part in arithmetic operations too.
Finally we convert the decimal part to add up to feets and the fraction part to the inches.  By this way you can easily overload operators for your own types.

Implicit and Explicit Cast

Implicit cast means automatic cast from one data type to another. Say you declare
int i = 10;

Now if you do
double d = i;

It lets you to do this. This is because of the fact that double is actually capable of holding any integer value.  This is called implicit cast operation. Compiler also does implicit casts itself.

Say you define class A and class B, so that B inherits A. So you can say :
B b1 = new B();
A a1 = b1;

This is also implicit cast operation, but here the cast is done automatically by the compiler, as compiler knows that any object of derived class can be held by the base reference.  So the first case is the example of framework defined implicit cast operation, while the second is the example of compiler defined implicit cast.


Explicit cast on the other hand requires the user to make sure that the cast is valid. Thus if you want to store a variable double to a variable int, there might be a case when the value produces OverflowException. So if the user want to defer the automatic detection of the cast operation, he can use Explicit cast operator.

double d = 10.0d;
int i = (int)d;

Here (int) makes the variable d to call its explicit cast operation which might throw OverflowException when value cannot be held to an integer variable.

Similar to this, the base class object when needed to refer to a derived class object, we also require an explicit cast.

Implicit Cast Operator Overload

Now as you are already clear about the implicit cast operation, let take the example a bit further to overload the implicit cast operators.

public static implicit operator int(Finch point)
{
    return point.Feet;
}

public static implicit operator float(Finch point)
{
    float value = point.Feet;
    value += (point.inch * 0.83f);
    return value;
}

public static implicit operator double(Finch point)
{
    double value = point.Feet;
    value += (point.inch * 0.83d);
    return value;
}
public static implicit operator decimal(Finch point)
{
    decimal value = point.Feet;
    value += Convert.ToDecimal((point.inch * 0.83d));
    return value;
}
public static implicit operator Finch(double point)
{
    decimal d = Convert.ToDecimal(point);
    Finch f = (Finch)d;
    return f;
}
In the above few static methods you have already seen that I have overloaded the cast operator using implicit keyword. This will ensure that we can implicitly assign an object of Finch to a int, double, decimal or float variable. The implicit cast operation will  call these static overloads and convert the value to appropriate types. As you can see the basic rules is you should always keep the overload operator as static.

Explicit Overload

On the contrary explicit overload requires an explicit call to the cast operators. The code looks almost similar with explicit keyword.

public static explicit operator Finch(decimal point)
{

    Finch newinch = new Finch();
    checked
    {
        newinch.Feet = (int)decimal.Truncate(point);
        var value = point - newinch.feet;
        newinch.inch = (int)(.83f / Convert.ToSingle(value));
    }
    return newinch;
} 

This will ensure that a decimal point can be cast to Finch explicitly.

Now let us invoke these overloads :
//implicit conversion of decimal to Finch
Finch f = 20.3;

//Invoke + operator overload
f = f + 2;
Console.WriteLine(f.ToString());

//cast to a double
double d = f;
Console.WriteLine("Double Part {0}", d);

//Cast to an integer
int i = f;
Console.WriteLine("Integer Part {0}", i);

Console.Read();

Download Source Code - 30KB

I hope you like my post. If you want to clarify anything regarding this post, feel free to comment.

Thank you.

6 comments:

  1. Worth revisiting the old concepts.

    ReplyDelete
  2. Great Tutorial. I don't get my you called your called finch though?

    ReplyDelete
  3. @Adam

    Are you using my implementation?
    If so, I would recommend to omit the +overload of using dynamic to double.

    Its no need to use dynamic in actual implementation, I used this to make it simple.

    ReplyDelete
  4. Hi Abhishek,
    I'm not using your actual code, but the code was instructive. I didn't know about implicit casting in c#.

    Also, I get it, Finch is some short form for FeetInch.

    ReplyDelete
  5. @Adam

    Cool. Even I dont expect others to use my code as it is not up to the mark. I have just concentrated on the feature not the code.

    Cheers

    ReplyDelete

Please make sure that the question you ask is somehow related to the post you choose. Otherwise you post your general question in Forum section.