Culture invariant Decimal.TryParse()
Asked Answered
P

5

54

I'm writing a custom string to decimal validator that needs to use Decimal.TryParse that ignores culture (i.e. doesn't care if the input contains "." or "," as decimal point separator). This is the suggested method:

public static bool TryParse(
    string s,
    NumberStyles style,
    IFormatProvider provider,
    out decimal result
)

I can't figure out what to use as the 3rd parameter. The examples I've seen look like this:

culture = CultureInfo.CreateSpecificCulture("en-GB");
Decimal.TryParse(value, style, culture, out number)

so they create a specific culture. CultureInfo does not have a "CreateInvariantCulture" method, and CultureInfo.InvariantCulture is not of the required type. What's the correct usage?

Postern answered 17/4, 2014 at 11:3 Comment(0)
P
13

In fact CultureInfo.InvariantCulture can be used here. The parameter expects IFormatProvider, an interface that CultureInfo implements. But InvariantCulture is invariant in the sense that it does not vary with the user's settings.

In fact, there is no culture that accepts either , or . as decimal separator – they are all one or the other. You'll have to find some other way to deal with data which can use either of these decimal separators.

Photographic answered 17/4, 2014 at 11:5 Comment(0)
P
6

My bad guys. I tested the following code:

string DutchDecimal = "1,5";
string EnglishDecimal = "1.5";
decimal a;
decimal b;
Console.WriteLine(decimal.TryParse(DutchDecimal, out a));
Console.WriteLine(a);
Console.WriteLine(decimal.TryParse(EnglishDecimal, out b));
Console.WriteLine(b);
Console.Read();

And indeed it does not parse the Dutch decimal correctly, instead it returns 15 in that case, ignoring the unrecognized ,. As it turns out the default parser behavior is hardcoded to use whatever the current culture is of the currently running thread.

Postern answered 17/4, 2014 at 11:48 Comment(5)
From the Microsoft Documentation it looks like .NET turns to your local system settings if you do not specify a culture: Parameter s is parsed using the formatting information in a NumberFormatInfo object initialized for the current system culture.Viviyan
Parsing 1,5 to 15 isn't really correct, is it? If ',' is a thousands-separator it shouldn't be allowed at the 10-position. I think parsing 1,5 using culture invariant parsing should fail.Molt
@Molt it is not correct to assume comma is a thousands-separator when it's not a decimal separator. For example, where Sweden would write "1,234,567.89", India would write "12,34,567.89" and China would write "123,4567.89". Number-formatting is not so straight-forward. My guess is, when the comma is not a decimal separator, it is just ignored completely by the parser.Resor
@Resor "1,234,567.89" is not correct in swedish. We use spaces as thousands-separator and comma as decimal-separator.Discussant
Actually it depends on your current locale, and in your case it seems is sees the point as the decimal separator. I have my locale set to dutch and it actually parses '1.5' to '15'. So if you rely now on it '1,5' to actually convert to '15' then you might be in for a suprise if your application is run on another computer with different locale settings.Ripon
G
3

I can't figure out what to use as the 3rd parameter.

Because all cultures NumberDecimalSeparator or NumberGroupSeparator etc.. are not the same.

Someones uses . as a NumberDecimalSeparator, someone uses , but there is no CultureInfo that uses both as a NumberDecimalSeparator.

CultureInfo implements IFormatProvider interface. That's why if you specify your CultureInfo, your value string try to be parsed on that cultures rules.

I'm writing a custom string to decimal validator that needs to use Decimal.TryParse that ignores culture

In such a case, you can use CultureInfo.Clone method to copy of which culture you want (or InvariantCulture) and you can set NumberDecimalSeparator and NumberGroupSeparator which string you want.

Gurtner answered 17/4, 2014 at 11:6 Comment(0)
R
1

This one works for me to parse decimals like 1.23:

decimal value;
string s = "1.23";
decimal.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out value);

// -> value = 1.23

it works independent from Windows locale, tested on a German Windows

Rawley answered 3/7 at 11:33 Comment(0)
S
0

I know this is a very old question, but it still pops up when searching for parsing with invariant culture.

I found the following in the documentation:

An invariant culture is culture-insensitive. Your application specifies the invariant culture by name using an empty string ("") or by its identifier.

So, using this knowledge, you can instantiate an invariant culture like this:

culture = new CultureInfo(string.Empty);
Selfrighteous answered 8/11, 2019 at 7:5 Comment(2)
CultureInfo already has an InvariantCulture public static property for this purpose.Ji
Not really an answer to the question, but still useful.Minacious

© 2022 - 2024 — McMap. All rights reserved.