Pages

Sunday, January 23, 2011

Different approaches to Casting

Conversion from one type to another is the most common programming need of our daily activities. We need cast operation almost for all applications we create. Few of them require regular type conversion while other requires you to specify the cast on an expression. In BCL, there are few libraries available to you which might help you to do this casting for you. All these are very specific to a situation and the choice between them is the one most of you are confused about. In this post, I will try to cover all of these scenarios and let you rethink it before writing conversions.

Implicit Type Conversion

This is the most basic conversion in which the type of the data is modified without any prior truncation of existing data. The implicit type conversion is automatic and does not require any special treatment to the instruction set. The implicit type conversion occurs when a variable of small integral type is stored into a reference of larger integral type or a derived class object is stored in base class reference. As for example

int i = 10;
long l = i;

Here the target time is larger in size than the source. Hence there is no probability of producing a truncation or a leak in this case and the compiler allows this conversion.

At the same time this rule is also valid for base – derived types where the derived class object can be cast easily to the base class as base class reference is lower in object hierarchy than derived class objects.

IEnumerable<object> lst = new List<object>();

Explicit Type Conversion

In case of explicit type conversion, the object is not converted automatically but it needs an explicit cast expression before the assignment. This cast is evaluated at runtime and compiler will generate an exception if the cast is not valid. The explicit cast can sometimes produce data truncate as either a large integral value is tried to store into a smaller type or base class object is tried to store in derived reference. For instance,




long l = 10;
int i = (int)l;

In the above case we need to explicitly specify the type cast to the expression. Hence in this case the explicit cast takes place.

If you look into IL, it will do a conv.I4 which means the 64 bit integer will be converted to 32 bit integer.

On the other hand, in case of reference types, you can even do the same using cast operation and it will call either explicit cast operator or will call the operator of base types. The explicit cast may generate InvalidCastException at runtime.

Userdefined Conversion

In case you need to define implicit or explicit cast for your own types you might also have an option to overload cast operators. The cast operator can be overridden so that based on object relationship you might easily do the conversion yourself.

You can read more about user defined conversion from
http://www.abhisheksur.com/2010/07/operator-overloading-with-implicit-and.html


Using the Library

.NET base class library provides you a number of classes that helps you to do these cast. System.Convert is one of the most important classes that let you change types.

Let me demonstrate this class a bit using my favourite tool Reflector.

Convert is actually a static class which enumerates all commonly known types into an array during its static construction. During each cast, the object is checked with the actual type and based on which the cast is properly taken. Lets look into Convert.ChangeType

The definition for the method looks like :



Here you can see, the ChangeType is actually breaks the entire cast into few parts.

  1. It checks whether the object we pass is null and the Type to which we are to convert is nullable, if so, it returns null
  2. It tries to cast the value to IConvertible, a generic interface from which every CLR type (like int, char, byte, etc) is inherited from. Thus if the value is any CLR Type, it should be cast as IConvertible. Otherwise InvalidCastException is thrown.
  3. Otherwise Type is checked and specific conversion is invoked. If the type is Object, it will return the value directly without any cast.

Thus ChangeType does nothing when you pass an User Defined Type while it does its own conversion when CLR Type is passed.

Now let me look how the CLR type conversion is executed. To do this, let me look into definition of System.Int32 (int)

So inside the type, the IConvertible is eventually calling the Convert classes. Now let me look into Convert.ToInt16, so we are going to cast an int32 into int16. The code would look like :


Hence, eventually every cast is internally a Conv call in IL. The BCL wrapper class Convert is actually the best implementation of implicit or explicit casts by properly throwing exceptions when data overflow occurs.


Note :
I must also address that System.Convert is at its best to handle nullables. It does automatic box/unbox effectively when it comes to the point of changing from value type to reference. During this conversion, the Convert methods automatically checks for null value and returns the default value for that particular type.


Casting an Anonymous Type

Anonymous type is new to .NET. It is introduced with .NET 3.5. The concept is very simple, anonymous types are created using new operator which ultimately creates a strongly typed class internally in IL after being compiled. You should remember, CLR is capable of finding appropriate type if the anonymous type appropriately matches another in the same assembly. Hence casting in anonymous type is possible if you know the structure of the object. Lets see the code below :

var x = new { X = 10, Y = 20 };
object boxedX = x;
//Now Unboxing
var unboxed = UnboxAnnonymousType(new { X = 0, Y = 0 }, boxedX);


// Now to get it unboxed

private static T UnboxAnnonymousType<T>(T example, object value)
{
    return (T)value;
}

In the above code the compiler automatically finds the appropriate anonymous type for the variable x which is created anonymously using new operator in the first line with properties to hold X and Y. So passing the object of same type to UnboxAnnonymousType appropriately cast the same type from object. Thus invokes castclass operator and the conversion is valid.


Conclusion

Even though this is the most basic article, but still I had fun creating this. Hope you find it useful.

Thanks for reading. Post your feedback.

No comments:

Post a Comment

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.