In my entry on “native” languages on the CLR, I made a blanket statement that the intrinsic VB conversion operators would be faster than the conversion functions in the Convert class because they compile down to IL rather than function calls. In my quest to emphasize my point, however, I made a serious misstatement which was not intentional but should be corrected. Not all intrisic operators compile down to simple IL instructions, although most do so. And the ones that don’t are worth discussing. So let me spend a moment talking about conversions.
The intrinsic conversion operators (CObj, CByte, CShort, CInt, CLng, CDec, CSng, CDbl, CDate, CStr, CChar, CType, DirectCast) generally fall into several broad categories of implementation:
- Conversions that are pure IL statements. The best example here is the conversion from Integer to Long or Long to Integer. This compiles directly down to a conv.i8 or conv.i4.ovf instruction, respectively. You really, really, really don’t want to be calling functions to do this kind of conversion unless you’ve got a lot of faith in inliners, which I generally don’t.
- Conversions that are mostly pure IL statements. The best example here is the conversion from Double to Integer. This compiles down to a call to Math.Round and then a conv.i4.ovf instruction. The purpose of the extra call is to implement banker’s rounding, which the CLR doesn’t natively support. (In banker’s rounding, a decimal number equidistant between two whole numbers is rounded to the nearest even number. So 3.5 rounds to 4, but 2.5 rounds to 2.) In this case, calling Convert.ToInt32(Double) is not the same as CInt(Double), and you have to choose which semantic you desire.
- Conversions that are calls to the Convert class. The Decimal type is not natively supported by the CLR. As such, conversions to and from Decimal (with the exceptions listed below) turn into calls to Convert.ToDecimal() or the appropriate helper. There’s no point in us reimplementing the conversion since it’s the same for both the CLR and VB. In this case, calling Convert.ToDecimal(Integer) is exactly the same as CDec(Integer).
- Conversions that call VB specific helpers. There are only two cases that fall into this category: conversions to and from String, and conversions from Object.
- Conversions to and from String call VB specific helpers because VB does a variety of extra things for you. For example, when converting String to Integer, we’ll parse decimal numbers and do the appropriate rounding. So while Convert.ToInt32(“10.5“) will barf with an exception, CInt(“10.5“) will work just fine. And this is just one example of the nice stuff that we’ll do for you. As always, though, extra functionality can equal extra cost. So if you just want the very basic functionality that Convert.ToInt32() calls (or you prefer calling two functions), you might get slightly better performance by calling it instead of using CInt on a String.
- Conversions from Object call VB specific helpers because VB needs to be able to implement VB specific semantics (such as the String conversions and banker’s rounding) when converting values from one type to another. For example, Convert.ToInt32(CObj(“10.5“)) still throws an exception, while CInt(CObj(“10.5“)) won’t.
One interesting thing to note is that if you really want only the CLR conversions and nothing else, the DirectCast operator will turn off most of the VB-specific conversion features (I believe we still do banker’s rounding, though). Then you can call the Convert class methods when you run into conversions that DirectCast doesn’t support. I still think that this is an extreme way to go about things, but I know some people are just that way. Me, I use the regular VB operators and then look out for performance sensitive areas where I might need something different.
Paul,
Great post. I also post a graphical choice for conversion awhile back at http://ipattern.com/simpleblog/PermLink.aspx?entryId=7
let me know what you think.
Maxim
[www.ipattern.com do you?]
Paul,
Very informative post, thank you. This is my first post on your blog, but I am a long time reader – this is one of the few informative/useful VB.NET-centric web logs I’ve found. Great job!
Anyways, I had a question regarding where the CType() function in VB.NET falls into your above categories. Does CType() translate directly to the VB-specific conversion functions such as CInt(), or is it the same as using Convert.ToInt32. or something entireley different? There’s been some discussion at my work in regards to CInt vs CType(obj, Int32) usage [and other datatypes as well].
Kevin
This is the one blog I read everyday now.
This article is VERY useful – thank you!
"Me, I use the regular VB operators and then look out for performance sensitive areas where I might need something different."
What kind of performance drag can the regular VB operators cause? It has never even occurred to me to use anything else (although I am new to VB.NET and admittedly haven’t mastered all the nuances of squeezing maximum performance from the language and framework).
Thanks for all the good comments!
Maxim: I like it!
Kevin: CType and the other operators are completely equivalent. So CType(x, Int32) is exactly the same as CInt(x).
Christopher: For example, the extra work we do converting strings to integers might not be necessary in your app. If there is a conversion from string to integer that happens a huge amount, the extra overhead might make a difference. But I would really only use alternatives if you’ve proven there’s a performance issue in your app.
Paul: OK, I get what you’re saying. Great article. I’m going to crib from your work liberally next time I have to do a white paper that has anything to do with type conversions. 😉
I use DirectCast a lot when casting objects down an inheritance chain.
Dim c As Control
…..
If TypeOf c Is MyControl Then
DirectCast(c, MyControl).DoSomethingCool()
End if
Is it better to use CType instead in this situation?
Beth: No, you’ll get exactly the same behavior in the case where you are casting down the inheritance hierarchy unless you are casting from Object. In that case, you lose extra features using DirectCast but can gain extra performance.
Pingback: Dave Donaldson's Blog
Pingback: VS Data Team's WebLog
Pingback: VS Data Team's WebLog
Cast from string "1~" to type ‘Integer’ is not valid
I wonder how Val("10.5") compares to CDbl("10.5"). One difference is that Val("10.5XYZ") does produce 10.5R instead of an exception.
Wat is the Replacement of CType function in VB 6
rather how can i implement CType function in VB 6???
Can anyone help me…..
Thx in Advance,
Santhosh
I get a ‘cannot convert from string to double’ error with the line in the following FOR loop. I’ve tried ceaseless combinations to no avail. Any ideas?
For Each m As Match In re.Matches(dataLine)
dblArr(i, j) = CDbl(m.Value)
Next
Ignore previous post — I’m an idiot! — I didn’t notice the comma at the end of my string! Grrr!
Cast from String (”) to Integer is not valid.
i would like to have infomation or help regarding vb source code or script for how to convert total sum into textual description or words in a vb textbox on a form.
my email is achichu@yahoo.com. do provide me with the source code information. i have tried a lot. and i have to give exam.
thank you.
i have a usercontrol with datagridview inside and i’d like to obtain datagridview with a cast, there is a way to do it without inherit from datagridview?
Thanks
how to convert a Sting into an object?
Is there a way to disable "Bankers Rounding" in visual basic. I can set the project properties to explicit to force me to cast all math, but then I would use C++, not visual basic for the program.
Example:
Dim iValue as integer
iValue=5.8
Now iValue should equal 5 not 6.
I could code it
iValue=int(5.8)
to get the correct behaviour but this is a pain
Hi PPL,
I will ask you a simple question..but if you have a solution you’re a genius!!
So… if i write in coding this:
Dim sStr As String
sStr = 5 + 5 * 3
sStr will become 20
But how can I have the answer of that formula stored in variable sStr IF THE FORMULA IS INPUTTED IN A TEXTBOX???????
I have done a lot of research and tried the CInt – CObj syntax on my String to Integer conversion and it still errors out as an Invalid conversion format.
Can someone please help. I am a new VB.Net programmer and need this code to run. Many thanks,
Jeff Tomaski
<%@ Page Language="VB" MasterPageFile="~/pts3.master" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="Proj_Active_Default" title="Untitled Page" %>
<script runat="server">
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Session("DateCount") = LblDateCount.Text
Session("MNTCount") = LblMNTCount.Text
Session("PACCount") = LblPACCount.Text
If Not (Session("DateCount") Is Nothing) Then
Dim vDateCount As Integer = CInt(CObj("DateCount"))
End If
If Not (Session("MNTCount") Is Nothing) Then
Dim vMNTCount As Integer = Session("MNTCount")
End If
If Not (Session("PACCount") Is Nothing) Then
Dim vPACCount As Integer = Session("PACCount")
End If
If "DateCount" < 10 And "MNTCount" < 2 And "PACCount" < 2 Then
Response.Redirect("SiteInfo/SiteHome.aspx")
Else
Response.Redirect("Dell2950_CountError.aspx")
End If
End Sub
</script>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPH1" Runat="Server">
<asp:SqlDataSource ID="Sql_Mon_Wed_2007" runat="server" ConnectionString="<%$ ConnectionStrings:pts3Connection %>"
SelectCommand="SELECT * FROM [A_Mon_Wed_2007]"></asp:SqlDataSource>
<br />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><br />
<asp:Label ID="LblDate" runat="server" Text="Label"></asp:Label><br />
<asp:SqlDataSource ID="Sql_DateCountBySite" runat="server" ConnectionString="<%$ ConnectionStrings:pts3Connection %>"
SelectCommand="SELECT COUNT(sSiteCode) as DateCount FROM dbo.P_Dell2950 WHERE ([start_time] = @start_time)">
<SelectParameters>
<asp:ControlParameter ControlID="TextBox1" Name="start_time" PropertyName="Text" />
</SelectParameters>
</asp:SqlDataSource>
<asp:SqlDataSource ID="Sql_DateCountByMNT_tz" runat="server" ConnectionString="<%$ ConnectionStrings:pts3Connection %>"
SelectCommand="SELECT COUNT(sSiteCode) AS MNT_TZ FROM dbo.P_Dell2950 WHERE (start_time = @start_time) AND (mountain_tz = ‘Y’)">
</asp:SqlDataSource>
<asp:SqlDataSource ID="Sql_DateCountByPAC_tz" runat="server" ConnectionString="<%$ ConnectionStrings:pts3Connection %>"
SelectCommand="SELECT COUNT(sSiteCode) AS PAC_TZ FROM dbo.P_Dell2950 WHERE (start_time = @start_time) AND (pacific_tz = ‘Y’)">
</asp:SqlDataSource>
<asp:Label ID="LblDateCount" runat="server" Text='<%# Eval("DateCount") %>’ Visible="false"></asp:Label>
<asp:Label ID="LblMNTCount" runat="server" Text='<%# Eval("MNT_TZ") %>’ Visible="false"></asp:Label>
<asp:Label ID="LblPACCount" runat="server" Text='<%# Eval("PAC_TZ") %>’ Visible="false"></asp:Label><br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Button" />
</asp:Content>
hi PPl….
i would like ask you a simple question..
if i write in coding this:
Dim sStr As String
sStr = (11 / 5) * 2)
sStr will become 4.4 but i want the answer sStr = 5…
so what is the solution???? thanks…
How about:
Dim result as Double = (11 / 5) * 2
Dim rounded As String = Math.Ceiling(result).ToString
Pingback: Anonymous
Pingback: Anonymous