Since I’m on the cusp of rewriting the section in the VB language spec on DirectCast
so that it actually tries to make sense, I thought I’d talk about it here, since I don’t know how much people understand about this strange little operator. DirectCast
is a cast operator that has the same syntax as CType
and is useful in some narrow situations. But first, a little background…
You may have noticed that all VB.NET projects get a default reference to Microsoft.VisualBasic.DLL. It doesn’t show up in your list of references because you can’t remove it. Why? Because it isn’t possible to express all of the VB language in IL, so we sometimes have to rely on helper functions. A good example of this is conversions from Object. If you convert an Integer to Object, for example, the CLR will only let you convert it back to Integer. However, VB will allow you to convert it back to Long
, Double
, String
, etc. To make this work, the compiler emits a conversion from Object
as a call to a helper function. The helper function takes the Object
, looks at the type of the value contained in it and then does the appropriate conversion to the target type.
When we started working on Microsoft.VisualBasic.DLL, we decided to write all the language helpers (and all the familiar user functions like Left
, Right
, Mid
, etc) in VB. In addition to the fact that we like VB, it’s also a great way to dogfood the product. So we set about writing the helpers, but we quickly ran into a chicken-and-egg problem. Let’s say that we’re writing the helper that converts something typed as Object
to Integer
. It would contain code something like:
If TypeOf o Is Integer Then Return CInt(o) End If
See the problem? The CInt(o)
conversion tries to convert something typed as Object
to Integer
… which is going to call the helper again. And again. And again. Until you run out of stack space and die. The problem was there was no way to “escape” from the extra VB conversion semantics and say “just cast this directly to x type, forget about all the fancy stuff.” And that’s where DirectCast
comes in. The function of DirectCast
is to just give you the CLR supported conversions and none of the extra conversions that VB supports by use of a helper. So when you say DirectCast(o, Integer)
, if o
does not contain an Integer, you’ll get an exception, whereas CType(o, Integer)
will work if o
contains a Long
, Double
, String
, etc. As you can imagine, we use this all over the place in our helpers.
Ok, so now you’re asking: “So why isn’t this just something you hacked in for building your runtime? Why did you make it a full part of the language?” Well, one reason was that we wanted to follow the principle that we didn’t want to have to “cheat” to build our runtime – presumably, if we needed to do something, others might, too. (There are still a few minor cheats that we make when building our runtime, but that’s another blog entry.) And, as it turns out, there are some narrow situations where using DirectCast can make things a tiny bit fast than they might otherwise be. Essentially, if you know that what you’re converting is exactly what you say it is, then you can use DirectCast to bypass the little bit of overhead that you incur by using the runtime helper. The most common place I use it in my own code is when dealing with collections like ArrayList
:
Dim a As New ArrayList() Dim i As Integer a.Add(42) i = DirectCast(a(0), Integer)
In this case, I know that the thing I’m getting out of the ArrayList
is an Integer, so I skip the helper and go straight to DirectCast
. However, I only suggestion you use this in situations where you know it will work, and you think you need that extra little bit of performance. In the real world, you’re hardly ever going to notice the difference, so you might as well go with the more flexible conversion operators like CType
, CInt
, etc. But when you identify some place you need that extra little “oomph,” it can come in handy.
Very interesting item. I wish more people would write more stuff like this instead of endlessly debating the merits of RSS.
This was extremely interesting. Please continue to publish such gems. Thanks!
DirectCast quickly became one of our best friends
Nice entry Paul! I had DirectCast explained to me some time ago by Duncan MacKenzie when he used it in one of his Msdn articles and have used it from time to time since then.
Extending the Type inspection theme… is there merit for a VB == of the ‘as’ operator in C#? Is there one that I don’t already know about?
There is some performance merit in the ‘as’ operator, although the discussion is probably a bit more than will fit in a comment. I’ll make a note to address that in a near-future entry.
Thanks Paul… heh, I was actually having an offline discussion about the ‘as’ operator with someone that you probably know and he was questioning me as to *why* I’d want it. That actually made me think that, for all the times I’d use it, I doubt that I’d ever gain any real benefits from having it included – especially once Generics comes into play?
Pingback: Darrell Norton's Blog
Pingback: Julia Lerman Blog
Pingback: ardent coder
A very good article, which helped me in improving my coding performance
It sounds to me that DirectCast is NOT a conversion function. The only thing that DirectCast can do is clone object and pass the instance of the new object to specified variable. Is that true?
No, DirectCast is a conversion function in that it takes a value typed as one type and converts it to another type. The fact that the representation changes isn’t any different than the fact that CStr(1) doesn’t convert the value in place but returns a new String instance.
The real genius of this entry is the verbal use of dogfood.
Superb!
M
I am so happy that microsft made a thing to convert Integer to Integer.
I used to use
int1 = int2
But that is much better.
In order to appreciate this function one must understand what boxing and unboxing is, since the DirectCast operator allows you to disable unboxing for a value, and that is why the performance improves. How do boxing and unboxing works?
In order to improve performance Microsoft made 2 Object types:
Value Types = These are not allocated on the managed heap and there fore are not garbage collected (obvious performance advantage over reference types), they are stored in the threat stock. (integer, long, double, etc)
Reference Types = These are stored on the managed heap and therefore garbage collected.
For example take a look at this function:
Function MyFunc(byref value as Object) ..
If you try to call this function the following way:
Dim a as interger = 10
MyFunc(a)
This causes boxing to occur, why? Because (a) is value type and the parameter is a reference type. When boxing or unboxing is required it is obvious that performance will be affected. So, using DirectCast will allow you to turn off boxing/unboxing which will result in better performance.
Consider the following code:
1. Dim int1 As Integer = 1
2. Dim o As Object = i
3. Dim int2 As Integer = DirectCast(o, Integer)
My understanding is that step 2 will box i into a reference type and step 3 will unbox o as a value type.
I’m confused how the previous statement is true.
"This causes boxing to occur, why? Because (a) is value type and the parameter is a reference type. When boxing or unboxing is required it is obvious that performance will be affected. So, using DirectCast will allow you to turn off boxing/unboxing which will result in better performance. "
If I have to box a value, how can I convert it without unboxing? I would think that DirectCast would pull a value type from a reference type.
I understand the performance increase of DirectCast, but I don’t see how that allows you to circumvent boxing/unboxing.
kakridge, you are correct. If you look above, the entry says that DirectCast disables extra VB conversions, not the basic unboxing/boxing operations themselves. There’s no way to avoid that when casting value types to and from Object.
Pingback: eCarlos's blogspaze
I though using DirectCast is a way of saying to CLR not to bother the chacking during the unboxing. The actual action of boxing, which is taking the value out of the box, will happen. But the extra overhead of verifycation is ignored during the DirectCast which helps to improve the performance.
I’ve always used DirectCast, Now I know that CType is another one of those voodoo functions’ I’m glad I never used CType. Also why does DirectCast not work on enums, but CType does?
Thanks for this optimization comparison.
But, what should I use for the following statment?
i1 = IIf(bool1 = bool2, 2, 1) ‘ Warning: Implicit conversion from Object to Integer
Should I use:
i1 = CInt(IIf(bool1 = bool2, 2, 1))
or
i1 = Directcast(IIf(bool1 = bool2, 10, 20), integer)
And for string:
str1 = CStr(IIf(bool1 = bool2, str2, str3))
or
str1 = IIf(bool1 = bool2, str2, str3).ToString
or
str1 = Directcast(IIf(bool1 = bool2, str2, str3), String)
For the first one, either should be fine, but the second will be slightly faster. For the second one, probably the first case is the best.
Is this the best way to convert an Object to an ArrayList?
Thanks for that info. I often use treeviews, listboxes, listviews etc, and I often ownerdraw them, and place the object represented by the respective item in the tag property. So, when a treenode (for example) is selected, and I need the actual object it represents, I usually do something like: Dim w as Widget = CType(nd.Tag, Widget). From your explanation, I should be using DirectCast, as I know exactly what I am converting. However, this still requires boxing – would it be better for me, let’s say in the case of a treeview, to create an object that inherits treenode and add a ‘Widget’ property? Then use that instead of treenode to avoid the conversion entirely?
Thank you very much!
I wish more and more articles are publicshed for VB.NET =) i love C# **BUT** my new work requires vb.NET
ARGH! @_@
thanks again! =)
> go straight to DirectCast. However, I only suggestion you use this in situations where you know it will work
There are two situations where I don’t know it will work: 1) I’m not defining types that ensure type-safety or 2) I lost track of what types are being passed.
The propensity for (1) is why I have reservations about VB coders. (2) is a bug! DirectCast will help me find it as close to the source as possible.
OK, I have another problem with Direct Cast. First I am a new guy.
Object to convert a string to a webControl label.
Purpose: So I can enter exam answer through an array for examble QAnswerX (Text Box) with the questions being QLabelX (Label Button)
I have the following code for the label portion.
Dim QLabel As Object
QLabel = ("QLabel" & (i) & ".Text")
QLabel = DirectCast(QLabel, Label)
Now I get the unable to CAST error.
ANY HELP WOULD BE APPRECIATED.
The use of this is for the following line (MS SQL):
myCommand.Parameters.AddWithValue("@QLabel", QLabel)
Robert.W@msimail.com
Thanks Paul,
But I don’t understand why you (in response to Michel) recommended using:
str1 = CStr(IIf(bool1 = bool2, str2, str3))
over:
str1 = Directcast(IIf(bool1 = bool2, str2, str3), String)
" # re: DirectCast revealed 2/12/2006 6:00 AM Michel
Thanks for this optimization comparison.
But, what should I use for the following statment?
i1 = IIf(bool1 = bool2, 2, 1) ‘ Warning: Implicit conversion from Object to Integer
Should I use:
i1 = CInt(IIf(bool1 = bool2, 2, 1))
or
i1 = Directcast(IIf(bool1 = bool2, 10, 20), integer)
And for string:
str1 = CStr(IIf(bool1 = bool2, str2, str3))
or
str1 = IIf(bool1 = bool2, str2, str3).ToString
or
str1 = Directcast(IIf(bool1 = bool2, str2, str3), String)"
"# re: DirectCast revealed 2/13/2006 12:08 AM Paul Vick
For the first one, either should be fine, but the second will be slightly faster. For the second one, probably the first case is the best. "
Ben: In the case of casting Object to String, there isn’t any huge difference in performance between CStr and DirectCast, so I think the CStr is more understandable. But, really, either is fine.
Great post.
Where does TryCast fit in to all this?
And has any of this changed since the original post, in VS 2005 or 2008?
Thanks Poul,
Let dt.Rows(0)("pstring") defined as String datatype at the database. (pstring is the coloum name)
Dim vinteger as Integer
When I tried to cast as
vinteger =DirectCast(dt.Rows(0)("pstring") , Integer)
At the Design time, VS doesn’t give any warning or error even I was trying to cast string to integer. But at the run time an InvalidCastException is trown.
I know that at the directcast , the types of Objects must be the same as they declared at the very beginning.
My question is how can an object appear different at the design time and runtime?
Why not directcast warn me at the design time ?
One more question Paul,
The same problem may occur when casting with directcast for the viewstate and session object. As they both appear as object data type at design time, bu they can get different values at the run time.
Won’t I use directcast to datarow, session and viewstate objects ? And why?
I need a technical explanation, please
Thanks in advance
Pingback: Anonymous
What about the convert command. Like Convert.toInt32(value) ?
Thank you for your post,
Can you please clarify if Cbool create another instance of the object or it does return the same objet converted.