Type Casting in CLR – Introduction(C#)

Posted: October 24, 2010 in .NET, C#
Tags: , ,

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 (0×16)
  .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 (0×23)
  .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.

About these ads
Comments
  1. Karthik says:

    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!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s