Monday, December 30, 2019

Casting and Data Type Conversions in VB.NET

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: DirectCastCTypeTryCast 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 isnt a string already, then the code will throw a runtime exception. TryCast is even more restrictive because it wont 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) ... wont even compile. TryCast is useful when youre not sure what type of object youre 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 dont 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 arent part of the .NET CLR (Common Language Runtime) to perform these conversions. But remember that CType will also throw an exception if theString doesnt contain something that can be converted to an Integer. If theres a possibility that the string isnt an integer like this ... Dim theString As String George ... then no casting operator will work. Even TryCast wont work with Integer because its 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. Microsofts documentation for DirectCast specifically mentions casting with an Object type so thats what I used in my first performance test. Testing begins on the next page! DirectCast will usually use an Object type, so thats 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. Heres 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. Heres the result. (Experiments with larger and smaller numbers of iterations as well as repeated tests under different conditions didnt 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 wont work using DirectCast, not what will. Heres 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 cant use DirectCast (or TryCast, although they dont 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. Lets check the performance of Microsofts 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 youre not casting an Object type, youre better off not using DirectCast.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.