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.
Worth revisiting the old concepts.
ReplyDeleteGreat Tutorial. I don't get my you called your called finch though?
ReplyDelete@Adam
ReplyDeleteAre 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.
Hi Abhishek,
ReplyDeleteI'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.
@Adam
ReplyDeleteCool. 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
de ce nu:)
ReplyDelete