9

This line of code:

Console.WriteLine(Convert.ToInt32(“23,23”) + 1);

Throws an exception. This line of code:

Console.WriteLine(Convert.ToDouble(“23,23”) + 1);

Prints 2324.

Does anybody know why this is the case? I wouldn't think that anything good could come of the second conversion.

user7116
  • 63,008
  • 17
  • 141
  • 172
quillbreaker
  • 6,119
  • 3
  • 29
  • 47
  • 4
    Which just goes to show that you should use the overload that takes a NumberStyles and an IFormatProvider if you want to avoid surprises. – bdukes Jan 19 '10 at 14:59

6 Answers6

14

From the MSDN documentation of System.Double.Parse:

The s parameter can contain [...] a string of the form:

[ws][sign][integral-digits[,]]integral-digits[.[fractional-digits]][e[sign]exponential-digits][ws]

Here, the comma (,) stands for "[a] culture-specific thousands separator symbol".

To summarize: If your current culture's thousands separator symbol appears anywhere in the string, it is ignored by Double.Parse (which is invoked internally by Convert.ToDouble).


Int32.Parse(string), on the other hand, does not allow thousands separators in the string:

[ws][sign]digits[ws]

which is why your first example throws an exception. You can change this behavior for both Double.Parse and Int32.Parse by using an overload that allows you to specify NumberStyles, as explained by the other answers.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • But why is this different for `Integer.Parse` then? Don’t thousands separators make equal sense here? – Konrad Rudolph Jan 19 '10 at 14:53
  • @Konrad: I updated my answer. Int32.Parse only allows `[ws][sign]digits[ws]`. About the motivation behind this: No idea... – Heinzi Jan 19 '10 at 14:55
  • 1
    I would guess it's just an implementation difference (which may or may not have some rationale behind it). The MSDN documentation says that `Int32.Parse` only accepts `[ws][sign]digits[ws]` where `ws` is whitespace. It doesn't accept a thousands operator by default... – bdukes Jan 19 '10 at 14:57
  • "Int32.Parse, on the other hand, does not allow thousands separators" : The int.Parse method *does* support the thousands separator, it's just disabled by default. See my answer. – Mark Byers Jan 19 '10 at 15:02
8

The first fails because int.Parse doesn't allow the thousands separator by default. You can change that using NumberStyles:

int d = int.Parse("11,23",
                  NumberStyles.AllowThousands,
                  CultureInfo.InvariantCulture);

Now it works like the double version which does support thousands separators by default. They presumably succeed because "," when treated as a thousands separator by the parser is completely ignored - even though the comma sometimes doesn't make sense as a thousands separator.

Surprisingly, even this works:

double d = double.Parse("1,,1,2,3", CultureInfo.InvariantCulture);

In the above, d is set to the value 1123.0.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • Since there is only two digits following the `,` in the provided sample, isn't it more likely to be a decimal separator? – Jørn Schou-Rode Jan 19 '10 at 15:30
  • @Jørn: Whether it is interpreted as a comma seperator or a decimal separator is determined by the CultureInfo. I can see from the output from quillbreaker's second example that comma is his thousands separator, otherwise the output would be "24,23". – Mark Byers Jan 19 '10 at 15:35
6
Console.WriteLine(Convert.ToDouble(“23,23”) + 1);

In this case, the comma is being interpreted as your localization's group separator symbol, and is ignored. See http://msdn.microsoft.com/en-us/library/fd84bdyt.aspx.

Console.WriteLine(Convert.ToInt32(“23,23”) + 1);

In this case, you are using Int32.Parse, which doesn't support group separators by default.

The reasoning behind this is that the integer converter has no localization support by default, because localization adds an additional overhead and there is no reason to add it for a parser that doesn't need to interact with any symbols at all. You can, however, force the parser to support localization with some extra arguments:

int.Parse("11,23", NumberStyles.AllowThousands, CultureInfo.InvariantCulture);

Float/double conversion, on the other hand, have to support a decimal separator. In some cultures, this is ",", in others, it can be " " or ".". Since the function must support localization anyway, it would make no sense for it to only support some localization features by default. Otherwise, the implementation would confuse people who expect that since localization is supported for decimal separator, it would support other localization aspects as well.

David Pfeffer
  • 38,869
  • 30
  • 127
  • 202
  • int.Parse *does* support the thousands separator - see my answer. – Mark Byers Jan 19 '10 at 15:00
  • +1 for the explanation of the reasoning! You might want to write "...the *default* integer converter...", since `Int32.Parse(string, NumberStyles)` allows you to add localization support. – Heinzi Jan 19 '10 at 15:02
  • +1 for the reasoning, but then again, I wonder why the overhead of culture parsing is allowed for the double Parse (the default one)? – Keugyeol Apr 26 '14 at 03:45
  • @Keugyeol What other choice is there? Decimal numbers by definition need to have a separator to distinguish the whole and fractional part. – David Pfeffer Apr 27 '14 at 12:13
  • @David Well, yes, the default parser for the double even checks for things like 'NaN' but still, checking for thousands separator could be an additional burden (no matter how small or big it is). So it makes me wonder, in case for the integer parser, what could be the reason behind this decision of performance over consistency. – Keugyeol Apr 27 '14 at 12:34
1

Commas are ignored in the conversion to double. If you would like commas to generate an error, then you can use the Double.Parse(string, System.Globalization.NumberStyles) method.

Jeffrey L Whitledge
  • 58,241
  • 9
  • 71
  • 99
  • If the comma (number group separator) is placed after the decimal point it gives a format exception so I guess it is not really ignored but considered somehow. – Keugyeol Apr 27 '14 at 12:40
0

Because the double is assuming that the comma is a thousands separater, and ignores it. The Int32 Convert does not do that.

Charles Bretana
  • 143,358
  • 22
  • 150
  • 216
0
?double.Parse("23,23", System.Globalization.CultureInfo.InstalledUICulture);
23.23

?double.Parse("23,23", new System.Globalization.CultureInfo("en-US"));
2323.0
?double.Parse("23,23", new System.Globalization.CultureInfo("fr-FR"));
23.23

?double.Parse("23,23", System.Globalization.CultureInfo.InvariantCulture);
2323.0

the same thing for Convert.ToDouble:

?Convert.ToDouble("23,23", System.Globalization.CultureInfo.InvariantCulture);
2323.0
serhio
  • 28,010
  • 62
  • 221
  • 374