Since I’m still working on a VB.NET I start to understand the language more and more. It feels like working with PHP. There are so many hacks, many things happen without you knowing that it happens.
Consider the following classes defined:
class Foo {} class Bar : Foo { internal static Foo GetInstance() { return new Bar(); } }
In C# you would have:
Console.WriteLine(Bar.GetInstance() as Bar);
the ‘as’ operator tries to cast foo to an instance of Bar. If that doesn’t succeed it returns null.
The code gets compiled to something like this:
{
Foo __foo = Bar.GetInstance();
Console.WriteLine(__foo is Bar ? (Bar)__foo : (Bar)null);
}
Doing a cast:
Console.WriteLine((Bar)Bar.GetInstance());
Throws an exception if we cannot cast. So you need to do a try catch around it.
Those are the casting operators in C#.
VB.NET has a little bit more stuff.
I will list them briefly:
CType(obj, Type), DirectCast(obj, Type), TryCast(obj, Type) and some predefined functions like CBool, CStr, Cint.
DirectCast(obj, Type) is the equivalent of the (Type)obj. No problem. TryCast(obj, Type) is the equivalent of obj as Type. No problem either. The problem arrises when we use CType and or one of those predefined functions.
You’d expect CBool(obj) to result in (you cannot do TryCast on a valuetype, hence the DirectCast) DirectCast(obj, Boolean). But no.
Consider the following code:
Dim boolTest As Object = False Console.WriteLine(CBool(boolTest))
When compiled it gets converted to this:
Dim boolTest As Object boolTest = CBool(0) Console.WriteLine(Conversions.ToBoolean(boolTest))
You can take a look at the Conversions class with Reflector. It’s located in the Microsoft.VisualBasic dll (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.VisualBasic.dll) and the full name is Microsoft.VisualBasic.CompilerServices.Conversions.
CBool should just try a DirectCast in my opinion.
But CType has some more nuisances. We are still using the Foo and Bar classes defined above.
Consider this code:
Dim foo As Foo = Bar.GetInstance() Console.WriteLine(CType(foo, Bar))
Gets compiled to:
Dim foo As Foo Console.WriteLine(DirectCast(Bar.GetInstance, Bar))
Great, it uses DirectCast. So if the conversion fails it throws an exception…
Now the catch:
Dim test As Object = String.Empty Console.WriteLine(CType(test, String))
You’d EXPECT it to do a DirectCast but no, this is what gets emmited:
Dim test As Object Console.WriteLine(Conversions.ToString(String.Empty))
Again a roundtrip you don’t see…
That’s why I don’t like VB.NET. Too much happens behind the screens.
I know that you can program VB.NET without all of this (use DirectCast and TryCast yourself). But the problem is that all legacy developers use these functions because they don’t know better.
I wish these features where deprecated and only available for projects converted from VB6 code.
Kristof,
Nice article. Thanks for contrasting casting in the two languages so succinctly. Thanks for cutting to the chase on the “as” operator (C# returns null if “as” is unsuccessful) thus helping me to choose the equivalent in VB.NET, which is TryCast(). Since I write in 3 languages including Visual RPG for .NET (which has an “*as” operator), this article is worthy of a bookmark for future reference.
Rex