August 9, 2005
In .NET 1.1, TryParse is only available for the Double datatype. Version 2.0 of the framework extends TryParse to all the basic datatypes. Why do we care? Performance. Parse throws an exception if the conversion from a string to the specified datatype fails, whereas TryParse explicitly avoids throwing an exception.
Julia Lerman showed a screenshot of a cool little demo app demonstrating the performance difference between Parse and TryParse in a presentation of hers (ppt) that I stumbled across a few months ago. I was shocked how much faster TryParse was! I knew exceptions were slow, but.. wow.
The original source for this sample app was a BCL team blog entry from way back in October 2003. That code sample is pretty ancient by now, so I thought I'd pick it up and update it so that it at least loads in VS.NET 2005 beta 2. In the process of doing this, I found out that this little sample app has.. er.. some bugs. A lot of bugs, actually. Bugs that made this dramatic performance difference not so dramatic any more:
So, yeah, parsing with exceptions is quite a bit slower, but not "did someone just downgrade my computer to a 486?" slower. The general rule of avoiding exceptions in your primary code paths still applies. That said, it's not unreasonable to use exceptions for program flow when the situation warrants it, as Alex Papadimoulis points out:
I think that there's a general consensus out there that Exceptions should be limited to exceptional circumstances. But "exceptional" is a rather subjective adjective, so there's a bit of a gray area as to what is and isn't an appropriate use of Exceptions.
Let's start with an inappropriate use that we can all agree on. I can think of no better place to find such an example than TheDailyWTF.com. Although that particular block of code doesn't exactly deal with throwing exceptions, it is a very bad way of handling exceptions. At the other extreme, exceptions are appropriate for handling environment failure. For example, if your database throws "TABLE NOT FOUND," that would be the time to catch, repackage, and throw an exception.
But it's in the middle where there's a bit of disagreement. One area in particular I'd like to address in this post is exceptions to business rules. I mentioned this as an appropriate before, but noticed there was quite a bit of disagreement with that. But the fact of the matter is, exceptions really are the best way to deal with business rule exceptions.
Alex concludes that, in this case, using exceptions to propagate errors across the tiers is a better solution. He's willing to pay the exception performance tax:
Less code, less mess. Nanoseconds slower? Probably. A big deal in the context of a web request going through three physical tiers? Not at all.
I totally agree. As long as you're aware of the cost, this is a perfectly reasonable thing to do. An iron-clad adherence to the "avoid all exceptions" rule would be a net loss.
Download the updated TryParse demo VS.NET 2005 solution (17kb zip)
Posted by Jeff Atwood
You can use TryParse for any numbers in .NET 1.1. You just need to pass the appropriate arguments, then check the output is within MinValue and MaxValue of, say, Int32. Seems to work for me anyway, and I expect it's faster than using a Regex, though I haven't tested this.
Also, yes, I know there's an issue with ZIP files coming down corrupt from the webserver. I will work on fixing this today..
OK, I fixed the GZIP compression problem with ZIP files. Looks like one of the windows updates overwrote some sections of the metabase.xml file? At any rate, it's working now.
The fixed-width comments window on your blog is VERY annoying. I am considering never coming back to this blog because of this single issue. You need a refresher course in UI design. Never, never, force a fixed size window on a user like this. Very bad indeed!
Converting 1000 strings with success rate of 75, as your example:
Datatype Parse TryParse
Int32 2222 ms 0ms
Decimal 2147 ms 0ms
Double 3251 ms 0ms
DateTime 2354 ms 3ms
.NET 2.0 beta 2, Athlon 1800+
Ok so maybe I should run without debugging ;)
Datatype Parse TryParse
Int32 23 ms 0ms
Decimal 24 ms 0ms
Double 37 ms 0ms
DateTime 29 ms 4ms
Yes, I agree it's always better to have the knowledge to make a call one way or another, rather than go by a checklist of NEVER do this, or ALWAYS do this.
Knowledge is power :)
I thought you might have written your own blogging software Jeff.
I would think it would only take one dedicated day to replicate the features I can see here.
Although of course, I can't see the back-end administration interface, which is where most the complication typically is.
this is useful to know. Was converting a VB.NET app and it had a bunch of IsDate, IsNumeric function invokations that I wanted to replace with .NET equivalents, and could not find any easy and simple solutions.
Using a regex to check for valid numbers isn't failsafe at all. Did you consider things like locale-specific syntax (France uses a comma for decimal places, not a dot) and minimum and maximum possible values (I bet a string of a million 8s will pass your regex but fail to convert to a valid number)?
There have been some optimizations, but the difference is still there. Change the "success rate" to something below 100 percent to see it.
Nice article. But is there a performance penalty of including an Exception, if you know the exception is never bound to be hit.
I downloaded and ran the example in VS 2005 and the times on both parse and TryParse are identical.
I am running a HP laptop from 2006 1.6GHZ with 2 Megs of RAM. AMD Atalon 64. So me, sticking with TryParse. I need the exception handler.
One of the first things that our company always puts into our base project is a Utility class that has static methods like IsInteger and IsNumeric(allows decimals). This is very easy to accomplish with regex, and is a great deal cheaper than exceptions.
There's no excuse to do a blind Parse call without validating the input string first. This can be more difficult with using DateTimes due to the wide variety of ways that a date can be input, so I always avoid that by using a third-party calendar control, or by using drop-down lists.
This would be good functionality to throw into the .NET framework. Either the methods could be tied to the System.String class, or each of the respective types(Int32, Int64, Double, etc.).
I was going back thru the archives and re-read this post. Just for kicks I downloaded the project and ran it under Visual Studio 2008, still targeting the 2.0 Framework. The weird thing was, that the times for parse and tryparse came out the same, both under release and debug.
Now my question is, what is causing this behavior? Pretty sure it isn't my dual-core processor, as the app isn't multithreaded. Has Microsoft been back-optimizing the performance of the Framework?
I recently came across your post and have been reading along. I thought I would leave my first comment. I wonder how this pertains to Business Loans? I don't know what to say except that it caught my interest and you've provided informative points. I will visit this blog often.
Have the bugs been worked out yet or is this still in beta.
I know in my copper repipe business, people expect positive pre-determined results. I guess computing is a different animal entirely.