DirectCast revealed

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.

35 thoughts on “DirectCast revealed

  1. jhigh

    Very interesting item. I wish more people would write more stuff like this instead of endlessly debating the merits of RSS.

    Reply
  2. Darren Neimke

    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?

    Reply
    1. paulvick

      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.

      Reply
      1. Darren Neimke

        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?

        Reply
  3. Pingback: Darrell Norton's Blog

  4. Pingback: Julia Lerman Blog

  5. Pingback: ardent coder

  6. Stranger

    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?

    Reply
    1. paulvick

      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.

      Reply
  7. Iamdumb

    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.

    Reply
  8. S. Gonell

    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.

    Reply
  9. kakridge

    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.

    Reply
    1. paulvick

      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.

      Reply
  10. Pingback: eCarlos's blogspaze

  11. Asghar Panahy

    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.

    Reply
  12. John

    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?

    Reply
  13. 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)

    Reply
  14. Hal4UK

    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?

    Reply
  15. Ace Balasador

    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! =)

    Reply
  16. TomB

    > 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.

    Reply
  17. rtw

    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

    Reply
  18. Ben

    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. "

    Reply
    1. paulvick

      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.

      Reply
  19. Graham

    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?

    Reply
  20. Mehmet O.

    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 ?

    Reply
  21. Mehmet O.

    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

    Reply
  22. Pingback: Anonymous

  23. jordan

    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.

    Reply

Leave a Reply