Categories: C#

Parse and TryParse in C#

Often, our applications depend on external data sources that provide the string representations of .NET types. We have an option of using the Parse and TryParse methods to convert these string representations back to the base .NET types. 

The strings can be of any type ranging from numeric, date and time, boolean, chars, or enums. However, let’s focus on parsing numeric strings using Parse() and TryParse() in this article.

To download the source code for this article, you can visit our GitHub repository.

Let’s dive in.

The Parse() Method

We use the Parse() method to convert a string representation of a number to its numerical value. It returns the converted numerical value if the conversion is successful. The Parse() method throws an exception if the conversion fails. The exception can be:

  • an ArgumentNullException, if the input string is null
  • a FormatException, if the input string is of incorrect format
  • an OverFlowException, if the converted number exceeds the minimum or maximum range of the specified numeric type

Let’s look at the Parse() method overloads. 

Parse(String)

We are most likely to encounter this overload of the Parse() method. It converts a string representation of a number to its numerical value.

For the Parse() method to work, we need to pass a valid string. A valid input string would be a sequence of digits from 0 to 9. Optionally, we can also have a leading and trailing whitespace along with a leading sign (+/-).

Let’s demonstrate this with an example of the Parse(String) method from the System.Int32 class:

Assert.AreEqual(456, int.Parse("456"));
Assert.AreEqual(-4567, int.Parse("-4567"));
Assert.ThrowsException<FormatException>(() => int.Parse("3456.89"));
Assert.ThrowsException<OverflowException>(() => int.Parse("34343454574745"));
Assert.ThrowsException<ArgumentNullException>(() => int.Parse(null));

Parse(String, IFormatProvider)

This overload of the Parse() method converts a string representation of a number that is in a culture-specific format to its numerical value.

Let’s consider a culture where we denote positive numbers by a leading # sign. Hence, in this culture, the number 1234 would become #1234. However, #1234 is not a valid number in other cultures and would fail to convert. In such a scenario, we specify the culture using Parse(String, IFormatProvider):

var culture = new CultureInfo("en-US");
culture.NumberFormat.PositiveSign = "#";

Assert.AreEqual(1234, int.Parse("#1234", culture));
Assert.ThrowsException<FormatException>(() => int.Parse("#4567"));
Assert.ThrowsException<FormatException>(() => int.Parse("$4561", culture));
Assert.ThrowsException<OverflowException>(() => int.Parse("#34343454574745", culture));

A valid input string for Parse(String, IFormatProvider) is a sequence of digits from 0 to 9 with optional leading and trailing spaces along with a leading sign. 

Parse(String, NumberStyles)

This overload of the Parse() method converts a string to its numerical value based on the specified style of the number

We use the NumberStyles enum to specify the style elements such as separator symbols or exponential digits etc.

The combination of NumberStyles flags affect what a valid input string is. Along with the sequence of digits from 0 to 9, it may also contain leading and trailing signs, thousand operators, etc.:

Assert.AreEqual(3476, int.Parse("3476", NumberStyles.None));
Assert.AreEqual(76678, int.Parse("76678.0", NumberStyles.AllowDecimalPoint));
Assert.AreEqual(766780, int.Parse("766,780", NumberStyles.AllowThousands));
Assert.ThrowsException<FormatException>(() => int.Parse("$45,618", NumberStyles.AllowThousands));
Assert.ThrowsException<OverflowException>(() => int.Parse("56.89", NumberStyles.AllowDecimalPoint));

Parse(String, NumberStyles, IFormatProvider)

This overload of the Parse() method combines the former two overloads. We use it to convert a number’s string representation in a culture-specific format to its numerical value based on a specified style:

Assert.AreEqual(78, 
    int.Parse("78,000", 
        NumberStyles.Float | NumberStyles.AllowThousands, 
        new CultureInfo("fr-FR")));

Assert.AreEqual(78000,
    int.Parse("78,000",
        NumberStyles.AllowThousands, 
        new CultureInfo("en-GB")));

Assert.AreEqual(78, 
    int.Parse("78.000", 
        NumberStyles.Float, 
        new CultureInfo("en-US")));

Assert.ThrowsException<FormatException>(() => 
    int.Parse("$78,000", NumberStyles.Float, new CultureInfo("en-US")));

Assert.ThrowsException<OverflowException>(() => 
    int.Parse("78.567", NumberStyles.AllowDecimalPoint, new CultureInfo("en-US")));

Parse(ReadOnlySpan<Char>, NumberStyles, IFormatProvider)

This is a relatively newer overload of the Parse() method. It’s available in .NET versions Core 2.1 and above. We use it to convert a span of characters in a culture-specific format to a numerical value based on a specified style: 

Assert.AreEqual(78, 
    int.Parse("78,000".AsSpan(),
        NumberStyles.Float | NumberStyles.AllowThousands, 
        new CultureInfo("fr-FR")));

Assert.AreEqual(78000, 
    int.Parse("78,000".AsSpan(), 
        NumberStyles.AllowThousands, 
        new CultureInfo("en-GB")));

Assert.AreEqual(78, 
    int.Parse("78.000".AsSpan(), NumberStyles.Float, new CultureInfo("en-US")));

Assert.ThrowsException<FormatException>(() => 
    int.Parse("$78,000".AsSpan(), NumberStyles.Float, new CultureInfo("en-US")));

Assert.ThrowsException<OverflowException>(() => 
    int.Parse("78.567".AsSpan(), NumberStyles.AllowDecimalPoint, new CultureInfo("en-US")));

Thus, we conclude all the overloads of the Parse() method. Let’s turn our attention to the TryParse() method.

The TryParse() Method

The TryParse() method helps us avoid exceptions when parsing. Here, as a return value, we get a boolean flag indicating whether the conversion was successful. The last parameter contains the result of the conversion and is preceded by the out keyword.

In case of an unsuccessful conversion, the out parameter contains the default value of the specified type.

Because there is no exception handling involved, the TryParse() method performs better than Parse().

Let’s see which TryParse() overloads are available to us.

TryParse(String, Int32)

This is the most commonly used overload of the TryParse() method. We use it to convert a number’s string representation to its numerical value

The System.Int32 parameter contains the resulting numerical value if the conversion is successful or a zero in case of failure.

Let’s take the same example we did for Parse(String) and convert it to its TryParse() counterpart:

Assert.IsTrue(int.TryParse("45689", out int result));
Assert.AreEqual(45689, result);
Assert.IsFalse(int.TryParse("3456.89", out int formatNum));
Assert.IsFalse(int.TryParse("34343454574745", out int overflowNum));
Assert.IsFalse(int.TryParse(null, out int nullNum));

So, with TryParse() instead of throwing exceptions or coding by exceptions, we can use the returned bool flag to control our code flow.

TryParse(String, NumberStyles, IFormatProvider, Int32)

This overload of TryParse() is similar to Parse(String, NumberStyles, IFormatProvider). We use it to convert a string representation of a number in a culture-specific format to its numerical value based on the specified style.

Let’s continue using our examples for Parse(String, NumberStyles, IFormatProvider) to understand the difference:

Assert.IsTrue(int.TryParse("78,000", 
            NumberStyles.Float | NumberStyles.AllowThousands, 
            new CultureInfo("fr-FR"), 
            out int frNum));

Assert.AreEqual(78, frNum);

Assert.IsTrue(int.TryParse("78,000", 
            NumberStyles.AllowThousands, 
            new CultureInfo("en-GB"), 
            out int gbNum));

Assert.AreEqual(78000, gbNum);

Assert.IsTrue(int.TryParse("78.000", 
            NumberStyles.Float, 
            new CultureInfo("en-US"), out int usNum));

Assert.AreEqual(78, usNum);

Assert.IsFalse(int.TryParse("$78,000", 
            NumberStyles.Float, 
            new CultureInfo("en-US"), 
            out int floatNum));

Assert.IsFalse(int.TryParse("78.567", 
            NumberStyles.AllowDecimalPoint, 
            new CultureInfo("en-US"), 
            out int decimalNum));

TryParse(ReadOnlySpan<Char>, Int32)

We use this overload of the TryParse() method to convert a number’s span representation to its numerical value

This works similar to the TryParse(String, Int32) with the difference being ReadOnlySpan<Char> instead of String as the input parameter:

Assert.IsTrue(int.TryParse("45689".AsSpan(), out int result));
Assert.AreEqual(45689, result);

ReadOnlySpan<char> value = null;
Assert.IsFalse(int.TryParse(value, out int nullNum));
Assert.IsFalse(int.TryParse("3456.89".AsSpan(), out int formatNum));
Assert.IsFalse(int.TryParse("34343454574745".AsSpan(), out int overflowNum));

TryParse(ReadOnlySpan<Char>, NumberStyles, IFormatProvider, Int32)

This overload of TryParse() is similar to TryParse(String, NumberStyles, IFormatProvider, Int32). However, we pass ReadOnlySpan<Char> instead of a String here. 

We use it to convert a span representation of a number in a specified style and culture-specific format to its numerical value.

Hence, we can simply convert the method used for TryParse(String, NumberStyles, IFormatProvider, Int32) like:

Assert.IsTrue(int.TryParse("78,000".AsSpan(), 
            NumberStyles.Float | NumberStyles.AllowThousands, 
            new CultureInfo("fr-FR"), out int frNum));

Assert.AreEqual(78, frNum);

Assert.IsTrue(int.TryParse("78,000".AsSpan(),
            NumberStyles.AllowThousands, 
            new CultureInfo("en-GB"), out int gbNum));

Assert.AreEqual(78000, gbNum);

Assert.IsTrue(int.TryParse("78.000".AsSpan(), 
            NumberStyles.Float, 
            new CultureInfo("en-US"), 
            out int usNum));

Assert.AreEqual(78, usNum);

Assert.IsFalse(int.TryParse("$78,000".AsSpan(),
            NumberStyles.Float, 
            new CultureInfo("en-US"),
            out int floatNum));

Assert.IsFalse(int.TryParse("78.567".AsSpan(), 
            NumberStyles.AllowDecimalPoint, 
            new CultureInfo("en-US"), 
            out int decimalNum));

Parsing Other Numeric Strings

We’ve learned about parsing numeric strings using Parse() and TryParse(). However, the examples focus on System.Int32.

What about the other numeric types?

All the other numeric types have their respective Parse() and TryParse() methods with overloads similar to System.Int32.

So instead of an int.Parse(), we would use long.Parse(), double.Parse(), or a decimal.Parse() depending on whether the string representation (or span representation when applicable) is of a System.Int64, System.Double, or a System.Decimal number respectively.

The same is applicable for TryParse with long.TryParse(), double.TryParse(), decimal.TryParse() etc.

Conclusion

In the article, we learned about how the Parse and TryParse in C# work and their different overloads.

Parse() is useful in the scenarios where we care about the type of exception that can occur during failure to convert a string to its numerical value. Whereas, with TryParse() we get a better alternative in terms of performance and reliability by not having to deal with exception handling.

Hence, in cases where we don’t need the exact details of the exceptions, it’s almost always better to go with TryParse().

Code Maze

Share
Published by
Code Maze

Recent Posts

Remove Duplicates From a C# Array

In this article, we are going to share the different methods on how to remove…

Updated Date May 25, 2022

How to Mock HttpClient with Unit Tests in C#

Mocking HTTP requests for unit testing is important because of the prevalence of APIs in…

May 24, 2022

Validate User Input With Regular Expressions in Blazor WebAssembly

In this article, we are going to learn how to use regular expressions for user…

Updated Date May 23, 2022

How to Register Services for Different Environments in .NET

In this article, we are going to learn how to register services for different environments…

May 21, 2022

Code Maze Weekly #124

Issue #124 of the Code Maze weekly. Check out what's new this week and enjoy…

Updated Date May 20, 2022

How to Create a Comma-Separated String From a List of Strings in C#

In this article, we are going to learn how to create a comma-separated string from…

May 19, 2022