Casting and Data Type Conversions in VB.NET

Comparing the three casting operators: DirectCast, CType, TryCast

Working Late In Office
vgajic / Getty Images

Casting is the process of converting one data type to another, for example, from an Integer type to a String type. Some operations in VB.NET require specific data types to work. Casting creates the type you need. The first article in this two-part series, Casting and Data Type Conversions in VB.NET, introduces casting. This article describes the three operators you can use to cast in VB.NET - DirectCast, CType and TryCast - and compares their performance.

Performance is one of the big differences between the three casting operators according to Microsoft and other articles. For example, Microsoft is usually careful to warn that, "DirectCast ... can provide somewhat better performance than CType when converting to and from data type Object." (Emphasis added.)

I decided to write some code to check.

But first a word of caution. Dan Appleman, one of the founders of the technical book publisher Apress and a reliable technical guru, once told me that benchmarking performance is much harder to do correctly than most people realize. There are factors like machine performance, other processes that might be running in parallel, optimization like memory caching or compiler optimization, and errors in your assumptions about what the code is actually doing. In these benchmarks, I have tried to eliminate "apples and oranges" comparison errors and all tests have been run with the release build.

But there still might be errors in these results. If you notice any, please let me know.

The three casting operators are:

  • DirectCast
  • CType
  • TryCast

In practical fact, you will usually find that the requirements of your application will determine which operator you use. DirectCast and TryCast have very narrow requirements.

When you use DirectCast, the type must already be known. Although the code ...

theString = DirectCast(theObject, String)

... will compile successfully if theObject isn't a string already, then the code will throw a runtime exception.

TryCast is even more restrictive because it won't work at all on "value" types such as Integer. (String is a reference type. For more on value types and reference types, see the first article in this series.) This code ...

theInteger = TryCast(theObject, Integer)

... won't even compile.

TryCast is useful when you're not sure what type of object you're working with. Rather than throwing an error like DirectCast, TryCast just returns Nothing. The normal practice is to test for Nothing after executing TryCast.

Only CType (and the other "Convert" operators like CInt and CBool) will convert types that don't have an inheritance relationship such as an Integer to a String:


Dim theString As String = "1"
Dim theInteger As Integer
theInteger = CType(theString, Integer)

This works because CType uses "helper functions" that aren't part of the .NET CLR (Common Language Runtime) to perform these conversions.

But remember that CType will also throw an exception if theString doesn't contain something that can be converted to an Integer.

If there's a possibility that the string isn't an integer like this ...


Dim theString As String = "George"

... then no casting operator will work. Even TryCast won't work with Integer because it's a value type. In a case like this, you would have to use validity checking, such as the TypeOf operator, to check your data before trying to cast it.

Microsoft's documentation for DirectCast specifically mentions casting with an Object type so that's what I used in my first performance test. Testing begins on the next page!

DirectCast will usually use an Object type, so that's what I used in my first performance test. To include TryCast in the test, I also included an If block since nearly all programs that use TryCast will have one. In this case, however, it will never be executed.

Here's the code that compares all three when casting an Object to a String:


Dim theTime As New Stopwatch()
Dim theString As String
Dim theObject As Object = "An Object"
Dim theIterations As Integer =
    CInt(Iterations.Text) * 1000000
'
' DirectCast Test
theTime.Start()
For i = 0 To theIterations
    theString = DirectCast(theObject, String)
Next
theTime.Stop()
DirectCastTime.Text =
    theTime.ElapsedMilliseconds.ToString
'
' CType Test
theTime.Restart()
For i As Integer = 0 To theIterations
    theString = CType(theObject, String)
Next
theTime.Stop()
CTypeTime.Text =
    theTime.ElapsedMilliseconds.ToString
'
' TryCast Test
theTime.Restart()
For i As Integer = 0 To theIterations
    theString = TryCast(theObject, String)
    If theString Is Nothing Then
        MsgBox("This should never display")
    End If
Next
theTime.Stop()
TryCastTime.Text =
    theTime.ElapsedMilliseconds.ToString

This initial test seems to show that Microsoft is right on target. Here's the result. (Experiments with larger and smaller numbers of iterations as well as repeated tests under different conditions didn't show any significant differences from this result.)

--------
Click Here to display the illustration
--------

DirectCast and TryCast were similar at 323 and 356 milliseconds, but CType took over three times as much time at 1018 milliseconds. When casting reference types like this, you pay for the flexibility of CType in performance.

But does it always work this way? The Microsoft example in their page for DirectCast is mainly useful for telling you what won't work using DirectCast, not what will. Here's the Microsoft example:


Dim q As Object = 2.37
Dim i As Integer = CType(q, Integer)
' The following conversion fails at run time
Dim j As Integer = DirectCast(q, Integer)
Dim f As New System.Windows.Forms.Form
Dim c As System.Windows.Forms.Control
' The following conversion succeeds.
c = DirectCast(f, System.Windows.Forms.Control)

In other words, you can't use DirectCast (or TryCast, although they don't mention it here) to cast an Object type to an Integer type, but you can use DirectCast to cast a Form type to a Control type.

Let's check the performance of Microsoft's example of what will work with DirectCast. Using the same code template shown above, substitute ...


c = DirectCast(f, System.Windows.Forms.Control)

... into the code along with similar substitutions for CType and TryCast. The results are a little surprising.

--------
Click Here to display the illustration
--------

DirectCast was actually the slowest of the three choices at 145 milliseconds. CType is just a little quicker at 127 milliseconds but TryCast, including an If block, is the quickest at 77 milliseconds. I also tried writing my own objects:


Class ParentClass
...
End Class

Class ChildClass
    Inherits ParentClass
...
End Class

I got similar results. It appears that if you're not casting an Object type, you're better off not using DirectCast.