In this post and couple of posts to follow, we will discuss about the different type casting mechanisms supported by CLR and the three primary CLR supported languages C#,VB.NET and C++/CLI.To start with, lets take a look into the two possible kinds of conversion scenarios, that generally we come across.
Implicit Conversion
In the following C# code snippet below we are trying to convert a 32 bit integer to 64 bit integer.
int i = 10; long l = i;
Since the target type is larger in size there is no need of any special operators etc. and type conversion happens implicitly.The same is true for the following sample where we are converting a type to it’s base type.
object o = new List<int>();
Explicit Conversion
When we do the reverse thing i.e. something like converting a double to int or a base type to it’s derived type we need to perform explicit casting.The following code will never compile,
double d = 2.567; int j = d;
This will fail with the following compiler error:
Cannot implicitly convert type ‘double’ to ‘int’. An explicit conversion exists (are you missing a cast?)
So we need to perform explicit cast as shown below:
double d = 2.567; int j = (int)d;
This results in a loss of precision and variable j stores 2.The IL code for the same is shown below:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 26 (0x1a)
.maxstack 1
.locals init ([0] float64 d,
[1] int32 j)
IL_0000: ldc.r8 2.5670000000000002
IL_0009: stloc.0
IL_000a: ldloc.0
IL_000b: conv.i4
IL_000c: stloc.1
IL_000d: ldloc.1
IL_000e: call void [mscorlib]System.Console::WriteLine(int32)
IL_0013: call int32 [mscorlib]System.Console::Read()
IL_0018: pop
IL_0019: ret
} // end of method Program::Main
Here the following steps are executed:
- A 64 bit float value is pushed into the stack using ldc.r8 instruction
- This value is stored in a local variable using stloc
- This value is pushed onto the stack using ldloc from the local variable
- conv.i4 converts this to 32 bit integer
Let’s consider the following conversion for reference types:
List<int> l = new List<int>(); object o = l; List<int> l1 = (List<int>)o;
The IL code shown below contains an instruction called castclass which is used to perform the type casting operation
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 22 (0x16)
.maxstack 1
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> l,
[1] object o)
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: castclass class [mscorlib]System.Collections.Generic.List`1<int32>
IL_000e: pop
IL_000f: call int32 [mscorlib]System.Console::Read()
IL_0014: pop
IL_0015: ret
} // end of method Program::Main
The castclass instruction is used to cast instance of an object to class specified as its opcode or token.If the types are incompatible or cast is invalid, it throws as InvalidCastException.
Explicit can be performed using “as” operator as shown below:
List<int> l = new List<int>(); object o = l; List<int> l1 = o as List<int>; if (l1!=null) { Console.WriteLine("Cast Successful"); }
The IL code shown below indicates that now another instruction called isinst is used to perform the cast.
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 35 (0x23)
.maxstack 1
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<int32> l,
[1] object o,
[2] class [mscorlib]System.Collections.Generic.List`1<int32> l1)
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: stloc.1
IL_0008: ldloc.1
IL_0009: isinst class [mscorlib]System.Collections.Generic.List`1<int32>
IL_000e: stloc.2
IL_000f: ldloc.2
IL_0010: brfalse.s IL_001c
IL_0012: ldstr “Cast Successful”
IL_0017: call void [mscorlib]System.Console::WriteLine(string)
IL_001c: call int32 [mscorlib]System.Console::Read()
IL_0021: pop
IL_0022: ret
} // end of method Program::Main
The isinst instruction checks whether an instance of an object can be converted to class specified as its opcode or token.If the types are incompatible or cast is invalid it returns null otherwise it returns the object instance in the very same way as castclass operator.
In this post we have discussed about casting particularly using C#.In the next post we check out on the casting options provided by C++/CLI.
Hi ,
I just wanted to invite you to the indiblogger meet happening in Kolkata after 2 years at
CII
DC-36, Sector – 1, Salt Lake City
Kolkata – 700 064
Landmark: Behind City Centre.
Only 200 seats available. Entry is free with loads of fun. If you have not registered already, register here = http://www.indiblogger.in/bloggermeet.php?id=113 . See you there!