I think this scenario sums it up best why DirectCast has a false sense of compile-time type checking security for non-object (object keyword) type, and is just meant to be backspaced.
float f = 10;
long l = f;
Option Strict On
Dim f As Single = 10
Dim l As Long = f
A C# coder, upon discovering that float is not directly assignable to long and won't compile, will do this:
long l = (long)f;
Which is correct.
Now, let's turn to our VB.NET coder, upon discovering that float is not assignable to long and won't compile, will attempt this:
Dim l As Long = DirectCast(f, Long)
A few seconds later...
VB.NET programmer: "Please let me do my bidding, please compile, please...!!!"
After some Googling-fu and MSDN-browsing moments later:
VB.NET programmer: "Ah.. so I have to use this CLng or CType construct for casting variables"
Dim l As Long = CLng(f)
That is what I meant by DirectCast having a false sense of compile-time type checking security. DirectCast are just meant to be backspaced if a programmer doesn't know when and where they should be used. DirectCast is a security blanket that is not worn all the time.
How useful is DirectCast in this scenario if it will not be used after all?
[EDIT]
@Jules
I'm not purporting that all VB.NET programmers don't know what's the real use of DirectCast. Some of them really do know that DirectCast are just meant to be used for object types (and primitive types that are boxed in object) only.
One scenario where a VB.NET coder recoding existing C# code to VB.NET one will arrive at wrong conclusion, is with expected (be it rightly or not) languages symmetry to each other.
When he/she sees in the code this construct...
TextBox txt = (TextBox)sender;
...He/she will translate that to this:
Dim txt As TextBox = DirectCast(sender, TextBox)
Which is correct.
Now, because we programmers love symmetry, some of us (I might be too if I don't know CLng) will tend to convert this code...
/* Numbers are stored in file as float(component's file structure
is designed by 3rd party company) */
float f = file.ReadFloat(0);
long l = (long)f; // But we don't care about using the fractional part
...to this:
Dim f As Single = file.ReadFloat(0)
Dim l As Long = DirectCast(f, Long)
If a C# person is the one converting C# code to VB.NET, he will be frustrated for apparent lack of symmetry here.
But for a VB.NET person tasked to convert C# code to VB.NET, he will get the impression that C# compiler doesn't catches incompatible type assignments, while VB.NET catches it. Now, for that apparent discovery, will brag that VB.NET feature to his colleagues and some forums.
But lest be the VB.NET programmer makes the mistake of wrongly inferring the intent of first code. The C#'s code fragment above started its life like this was initially written like this:
float f = file.ReadFloat(0);
long l = f;
And that will not compile, C# compiler catches incompatible type assignments, in the same vein that the equivalent VB.NET with Option Strict On
will also not compile that (albeit will only not compile when Option Strict
is set to On
, too lenient). So we need to typecast float to long using (long)
. Becomes this: long l = (long)f;
Now for casting one variable type to another compatible type, in the same vein that we convert this code...
TextBox txt = (TextBox)sender;
...to this code:
Dim txt As TextBox = DirectCast(sender, Textbox)
We must convert this code...
long l = (long)f; // Will compile
...to this code:
Dim l As Long = DirectCast(f, Long) ' Will not compile
But alas, that will not compile. On casting between compatible primitive types, this is where DirectCast fells short in. It doesn't offer any symmetry to the C# code above, and it cannot be used on casting compatible primitive types, despite its name DirectCast.
The way I see it, DirectCast should be named CastObject, since it can only cast between object types (and also primitive types that are boxed in object) anyhow. DirectCast really has no business with assigning compatible primitive types (integer, double, and their lower and higher counterpart). When assigning between compatible primitive types, DirectCast ceases to be useful, especially you will backspace it anyhow, and replace it with proper one.
Or the other way I see it, DirectCast construct should be amended, so it can cast compatible types like the way old and newer languages do ever since, e.g., C, C++, C#, Java, Delphi, D, etc. Doing this, it will offer VB.NET significant symmetry to other languages when it comes to type casting. Doing this, we can also throw away (hypothetically only, we cannot make other programs fail that rely on old functions) all plethora of functions which names doesn't directly maps to its types (e.g., CInt, CDbl, CSng, etc.). We will just use DirectCast in lieu of them.
string s = "10"; int i = (int)s;
does not compile in C#. – Draftsmanint i = (int)d;
may perform a known conversion for a known type as in your example code, in any scenario where you'd realistically useDirectCast
in VB.NET (i.e., when an object's type is not known at compile time), casting with()
in C# does not perform a conversion -- it just casts. So a boxed double cannot be unboxed as an integer. For this reason the two are effectively equivalent. – JameljamersonSystem.Type
methodIsAssignableFrom
. – Mortmain()
is different thanDirectCast
are correct for value types, but incorrect for reference types. [The two are equivalent for reference types; no conversion is performed.] Which makes it a pointless comparison, because, IMHO, there is no reason to useDirectCast
with a value type. The way I see it:()
is equivalent toCType
for value types, and toDirectCast
for reference types. – Bondholder