Casting in Visual Basic NET

In all type safe languages there is the concept of “casting”, an operation used to specify to the compiler that a variable of a certain Type has to be considered of different Type. Visual Basic has three operators to do a cast: DirectCast, CTypeand TryCast, each one behaving in a different way from the other. To understand the subtle differences from these three operators lets present a simple example.

PrivateSub DirectCastExample(ByVal obj AsObject)
Console.WriteLine(“string lenght={0}”, DirectCast(obj, String).Length)

PrivateSub CTypeExample(ByVal obj AsObject)
Console.WriteLine(“string lenght={0}”, CType(obj, String).Length)

PrivateSub trycastExample(ByVal obj AsObject)
Console.WriteLine(“string lenght={0}”, TryCast(obj, String).Length)

PrivateSub Test()

The three instruction of the Test() function give really three different results, the first throws an InvalidCastException, the second writes “string length=2” and the third throws a NullReferenceException. To understand what is happening we could look at generated MSIL. DirectCast operator is translated with this code

L_0007: castclass string
L_000c: callvirt instance int32 [mscorlib]System.String::get_Length()

DirectCast is translated to castclass opcode, that simply pushes on the stack the object reference to the cast instance. If at run time the instance passed to the function is not a String class an InvalidCastException is thrown. DirectCast can convert if the object is of the exact type, if inherits from the type specified, or if the object implements the interface when the destination type is an interface.

TryCast operator behaves a little different, this is the MSIL generated

L_0007: isinst string
L_000c: callvirt instance int32 [mscorlib]System.String::get_Length()

TryCast use the isinst opcode, that is analogous to castclass, but if the cast is not successful instead of throwing an exception a null value is push on the stack. The third type of cast, CType is not really a cast operator, but instead a conversion operator, even if in a lot of documentation CType is considered to be a cast operator, to understand the difference here is generated MSIL.

L_0007: call string [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.Conversions::ToString(object)
L_000c: callvirt instance int32 [mscorlib]System.String::get_Length()

As you can see CType operator calls internally the function ToString() of class Microsoft.VisualBasic.CompilerServices.Conversions, this means that CType does not make a cast, but it makes conversions. The example in fact reveals that when we pass the integer value 30 to the function, this value gets converted to the string “30” and the code does not throw errors. The annoying issue is that you use CType to convert a variable to a custom type class it defaults to use castclass opcode, since the Microsoft.VisualBasic.CompilerServices.Conversion has methods to convert only to.NET basic types.