Parsing Performance (If, TryParse, Try-Catch)
Always use T.TryParse(string str, out T value). Throwing exceptions is expensive and should be avoided if you can handle the situation a priori. Using a try-catch block to "save" on performance (because your invalid data rate is low) is an abuse of exception handling at the expense of maintainability and good coding practices. Follow sound software engineering development practices, write your test cases, run your application, THEN benchmark and optimize.
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%" -Donald Knuth
Therefore you assign, arbitrarily like in carbon credits, that the performance of try-catch is worse and that the performance of TryParse is better. Only after we've run our application and determined that we have some sort of slowdown w.r.t. string parsing would we even consider using anything other than TryParse.
(edit: since it appears the questioner wanted timing data to go with good advice, here is the timing data requested)
Times for various failure rates on 10,000 inputs from the user (for the unbelievers):
Failure Rate Try-Catch TryParse Slowdown
0% 00:00:00.0131758 00:00:00.0120421 0.1
10% 00:00:00.1540251 00:00:00.0087699 16.6
20% 00:00:00.2833266 00:00:00.0105229 25.9
30% 00:00:00.4462866 00:00:00.0091487 47.8
40% 00:00:00.6951060 00:00:00.0108980 62.8
50% 00:00:00.7567745 00:00:00.0087065 85.9
60% 00:00:00.7090449 00:00:00.0083365 84.1
70% 00:00:00.8179365 00:00:00.0088809 91.1
80% 00:00:00.9468898 00:00:00.0088562 105.9
90% 00:00:01.0411393 00:00:00.0081040 127.5
100% 00:00:01.1488157 00:00:00.0078877 144.6
/// <param name="errorRate">Rate of errors in user input</param>
/// <returns>Total time taken</returns>
public static TimeSpan TimeTryCatch(double errorRate, int seed, int count)
{
Stopwatch stopwatch = new Stopwatch();
Random random = new Random(seed);
string bad_prefix = @"X";
stopwatch.Start();
for(int ii = 0; ii < count; ++ii)
{
string input = random.Next().ToString();
if (random.NextDouble() < errorRate)
{
input = bad_prefix + input;
}
int value = 0;
try
{
value = Int32.Parse(input);
}
catch(FormatException)
{
value = -1; // we would do something here with a logger perhaps
}
}
stopwatch.Stop();
return stopwatch.Elapsed;
}
/// <param name="errorRate">Rate of errors in user input</param>
/// <returns>Total time taken</returns>
public static TimeSpan TimeTryParse(double errorRate, int seed, int count)
{
Stopwatch stopwatch = new Stopwatch();
Random random = new Random(seed);
string bad_prefix = @"X";
stopwatch.Start();
for(int ii = 0; ii < count; ++ii)
{
string input = random.Next().ToString();
if (random.NextDouble() < errorRate)
{
input = bad_prefix + input;
}
int value = 0;
if (!Int32.TryParse(input, out value))
{
value = -1; // we would do something here with a logger perhaps
}
}
stopwatch.Stop();
return stopwatch.Elapsed;
}
public static void TimeStringParse()
{
double errorRate = 0.1; // 10% of the time our users mess up
int count = 10000; // 10000 entries by a user
TimeSpan trycatch = TimeTryCatch(errorRate, 1, count);
TimeSpan tryparse = TimeTryParse(errorRate, 1, count);
Console.WriteLine("trycatch: {0}", trycatch);
Console.WriteLine("tryparse: {0}", tryparse);
}
What is better: int.TryParse or try { int.Parse() } catch
Better is highly subjective. For instance, I personally prefer int.TryParse
, since I most often don't care why the parsing fails, if it fails. However, int.Parse
can (according to the documentation) throw three different exceptions:
- the input is null
- the input is not in a valid format
- the input contains a number that produces an overflow
If you care about why it fails, then int.Parse
is clearly the better choice.
As always, context is king.
How do I use TryParse or Try catch to explain to the user what he's doing wrong?
The compiler has detected that, if your try
block throws an exception before TryParse
runs, the number
variable will never have a value assigned to it, so it won't allow you to use it later on.
Even when you're sure the code inside the try
block couldn't possibly fail, the compiler is not.
int number;
try
{
Int32.TryParse(Console.ReadLine(), out number);
}
catch
{
Console.WriteLine("This only works with numbers!");
}
if (number < gameNumber) // if "try" fails, number is undefined
You're part way there. The call to TryParse
already returns false
if the conversion failed, so use that return value to decide when to display an error message to your user.
int number;
if (!Int32.TryParse(Console.ReadLine(), out number))
{
// parse failed ("number" is now 0), display message to user
Console.WriteLine("This only works with numbers!");
// start the next iteration of the loop, prompting the user again
// (otherwise, the number comparison runs, telling the user their guess is too small)
continue;
}
if (number < gameNumber)
Parse v. TryParse
Parse
throws an exception if it cannot parse the value, whereas TryParse
returns a bool
indicating whether it succeeded.
TryParse
does not just try
/catch
internally - the whole point of it is that it is implemented without exceptions so that it is fast. In fact the way it is most likely implemented is that internally the Parse
method will call TryParse
and then throw an exception if it returns false
.
In a nutshell, use Parse
if you are sure the value will be valid; otherwise use TryParse
.
pros and cons of TryCatch versus TryParse
TryParse
will be faster than catching an exceptionTryParse
indicates something expected - nothing exceptional is happening here, it's just that you suspect your data may not be valid.TryParse
isn't using exception handling for normal control flow
Basically, go with TryParse
:)
By the way, your code can be rewritten as:
public static double GetDouble(object input, double defaultVal)
{
double parsed;
return double.TryParse(input.ToString(), out parsed)) ? parsed : defaultVal;
}
C#: When should I use TryParse?
It's pretty much as simple as this: Use Parse
if you want an exception when you encounter invalid data; use TryParse
if you don't. Your question seems, therefore, to be:
Why would you not want an exception if data is invalid?
Exceptions should only be used for exceptional cases, and the data being invalid might not be an exceptional case. Maybe you're writing a data cleansing program that's expecting to get invalid data and will try to infer what a reasonable value is when the data is invalid. Maybe the data isn't all that important and you can just skip the record that contains it.
It depends on context, and having the choice of Parse
and TryParse
methods lets you choose the appropriate parsing mechanism for yours.
Parsing with TryParse or Parse when data is theoretically always correct?
I look more at the scenario than the performance; if the expected behaviour is that it is valid, I generally use Parse (or ParseExact if available), and let the exception go. Unless I need to raise a specific error, in which case TryParse is handy.
If the data might be (say) an integer, then TryParse is preferable over Parse+catch.
With LINQ-to-XML: don't parse; instead, use the static conversion operators provided; so rather than:
...
select int.Parse(node.Value);
you should use
...
select(int) node;
this is even more important for things like DateTime, as it takes into account the standard XML formats. It also does the "expected" thing if the node doesn't exist (i.e. node
is null
):
select (int?)node;
will return a null
value rather than throwing a NullReferenceException
(which node.Value
would do). There are static conversion operators for most expected data-types.
Which one is faster in processing and conversion int.Parse(), int.TryParse(), Convert.Int32()
Go read this ("Performance Profiling Parse vs. TryParse vs. ConvertTo") for much add'l info.
If you are unsure if the string is parsable, then int.TryParse()
will be MUCH faster than either of the others and catching the exceptions.
Java Scope Issues: try-catch block, parsing String to Date
You need to define the variable outside the try scope, then use it from inside. This code will work to your expectation:
String stringDate = sc.next();
SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
Date date = null;
try {
date = dateFormatter.parse(stringDate);
} catch(ParseException e) {
e.printStackTrace();
}
e = new Employee(id, login, salary, date, name);
You need to watch out now as while you create the new employee the date might be null. Therefore you might even go one step further and do that only if the date is not null. But in the snippet you have here the variable e is not defined anyway (or just used in the catch block).
String stringDate = sc.next();
SimpleDateFormat dateFormatter = new SimpleDateFormat("MM/dd/yyyy");
try {
Date date = dateFormatter.parse(stringDate);
e = new Employee(id, login, salary, date, name);
} catch(ParseException e) {
e.printStackTrace();
}
Related Topics
How to Catch All Exceptions/Crashes in a .Net App
How to Resize Image in C# Winrt/Winmd
How to Bind Datatable to Datagridview in C#
How Does One Extract Each Folder Name from a Path
Jquery Ajax Call to an ASP.NET Webmethod
Could Not Load File or Assembly 'System.Web.Http 4.0.0 After Update from 2012 to 2013
Automatically Update Version Number
Draw on the Screen Without a Form
How to Get All the Ad Groups for a Particular User
Sending Windows Key Using Sendkeys
How to Change Another Program's Window's Size
Get the Id of Inserted Row Using C#
Func Delegate with Ref Variable
Discovering Derived Types Using Reflection
How to Get a Character in a String by Index
When Would You Use Delegates in C#
In C# Differencebetween a Destructor and a Finalize Method in a Class