I’ve done quite a bit of VB.NET maintenance lately.
Most of that code was riddled with CType, both for conversions and casts. Quite a bit code had Option Explicit and Option Strict Off. A lot of those CType constructions had empty Try / Catch / End Try blocks around them.
Those empty catch blocks are a code smell. They pretend to be able to survive any exceptional disaster, but in practice you can’t. You have to indicate what kinds of disasters you can handle, for instance if a meteorite hits your data center (thanks George Stocker).
Turning off Option Strict can be OK under many circumstances (the default is off), but having Option Explicit off is usually a code smell as well, just like On Error Resume Next (which was also in plenty of the source code).
I do understand a lot of VB.NET source comes from people having programmed in VB 6, VBScript or VBA for a long time where those constructs were more common. But writing code in the 21st century is much more about writing code that you can prove to be right. Having proper error handling and compiler type checking is a big part of that.
It pays to go with the idiom, for example read the good and bad ways of vb.net – Safest way to check for integer.
Back to CType: basically you have do distinguish between conversions and casts. The reason is that when you know it will be a form of cast, CType is way to expensive. And if you know you will be doing conversions, than casting is not what you want.
Casting
When performing casts from a reference to a type, you have these options (both of which are way cheaper than CType):
- DirectCast will throw an exception if the cast cannot be performed (only if a downcast fails: the reference does not implement the type)
- TryCast will return null if the cast cannot be performed
Note that TryCast was not in the VB.NET 1.0 and 1.1 versions, it got added in VB.NET 8 as part of Visual Studio 2005: TryCast (aka. the ‘as’ operator) | Panopticon Central.
Note that DirectCast often goes with checking the type using the TypeOf and Is operators. See Cody Gray explaining the TypeOf operator in How to check if an object is a certain type.
Conversions
For conversions, there are more options:
- When you do need specific type conversion functions, you can either
use CType or any of the VB.NET built-in specific Type Conversion Functions to perform an explicit conversion,
or use the generic .NET System.Convert.ChangeType Method: this makes your code more portable across .NET languages.Note that the CType and built-in specific type conversion operators will often generate more code behind the scenes. Take a look at VB.NET Casting vs C# casting | Kristof’s blog for more information on that.
- For widening conversions, you don’t have to do anything: they work implicitly.
- For narrowing conversions, use type conversion functions but be prepared for the exceptions InvalidCastException and OverflowException.
- For conversions from string to numeric, use the VB.NET built-in Val function as explained in Conversions Between Strings and Other Types.
- When converting from Object to something else, do not use the Microsoft CType example; use specific type conversion functions.
- Be careful with Array Conversions, as for successful conversion, usually the arrays will become of a type that is too general (like an Object Array).
Thou you can have Fun With Dynamic Objects (Doug Rothaus), when using Dynamic Objects, conversion gets a lot trickier. Be prepared to research more into these areas:
- Override the DynamicObject.TryConvert Method.
- Override the DynamicMetaObject.BindConvert Method.
- Call one of the Conversion.CTypeDynamic Method overloads.
Additional reading
This article was about VB.NET specific code smells. There are more generic ones, as you can write crappy code in any environment. Just read some of Coding Horror: Code Smells to get a feel for it.
If you want to get rid of On Error Resume Next, read what Tim Medora has answered to What is the best alternative “On Error Resume Next” (especially the part about logging exceptions).
Did I already mention that Empty Try Catch blocks are a bad idea?
Since more than a decade, the CType/DirectCast topic has come up on many sites and forums.
A few interesting posts and abstracts:
- Joel Coehoorn answering Difference between DirectCast() and CType() in VB.Net – Stack Overflow.
- This classic Visual Basic .NET Internals from 2003 is still very much worth reading.
- 2003: Cheat Sheet – Casting in VB.NET and C# – CodeProject.
- 2007: DirectCast vs. CType – CodeProject.
I like the summary table by Thorsten(kaefer) over various languages mentioned in his Swamp answer:
I would like to see a discussion on the differences, advantages, and different situations in which each of these are best used within the context of .NET programming for Autocad.
CType is the odd one out, since it performs some dark magic outside of the CLR, and can be used to emulate Option Strict Off. An older article on msdn discusses this, under “Conversion Functions, CType, DirectCast, and System.Convert”.
As for the others, it should be pretty straightforward to map type conversions between .NET languages.
VB.NET C# F# upcast, inheritance or implementation required, can’t fail DirectCast (<type>) :> or upcast downcast, inheritance or implementation required, may throw InvalidCastException DirectCast (<type>) :?> or downcast conversion, inheritance or implementation required, may return null TryCast as <type> type test TypeOf is <type> :? type conversion functions CInt, CDbl etc. int, float etc. I’m not quite sure how conversions to and from System.Object (boxing/unboxing) fit into this picture.
Cheers, Thorsten
–jeroen
Filed under: .NET, .NET 1.x, .NET 2.0, .NET 3.0, .NET 3.5, .NET 4.0, .NET 4.5, Development, Software Development, VB.NET, VB.NET 10.0, VB.NET 11.0, VB.NET 7.0, VB.NET 7.1, VB.NET 8.0, VB.NET 9.0 Image may be NSFW.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
