Reputation: 2435
I am migrating from an old MFC GUI to C#.
I was building a Form-based GUI when I've got an unexpected exception converting a string to an integer type. I assumed it would work the same as converting string to double.
string str = "1,000";
double dthou = Convert.ToDouble(str); // OK
int ithou = Convert.ToInt32(str); // raises an exception
Conversion to double gives correct value: 1000.0. For int conversion, I was able to get a solution : Convert.ToInt32() a string with Commas.
But I am curious if there were any reason behind this. Or, am I missing something?
I was able to find a similar, but not exactly a duplicate question : Number parsing weirdness
[EDIT] after learning about the culture issue.
I am in a kind of a culture-shock because until now, in Korea, both floating point number and integer numbers are expressed with "," for thousands group and "." for decimal point (at least in the real world, in Korea, I mean, I think... ). I guess I will have to accept current settings of MS Visual Studio and carry on.
[EDIT2] after sleeping over this issue.
I think it's more of the inconsistent handling of the formatted string. ToDouble accepts strings with thousands separator (in my culture, comma), but ToInt32 does not. If ToDouble
is float | allowThousands
, then why could'nt ToInt32
have been integer | allowThousands
is what I am asking.
Upvotes: 6
Views: 5768
Reputation: 98750
In your profile, it says you are from South Korea. That's why I assume your current culture is ko-KR
. (And you said as well.)
And it's NumberDecimalSeparator
is .
but it's NumberGroupSeparator
is ,
Your Convert.ToDouble
works and it assumes your ,
is a thousands seperator, not decimal seperator. That's why your dthou
will be 1000
not 1
.
Convert.ToInt32(string)
uses Int32.Parse(string, CultureInfo.CurrentCulture)
explicitly and this method implemented like;
public static int Parse(String s, IFormatProvider provider)
{
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}
As you can see this method uses NumberStyles.Integer
as a default. And that's why your string can be successfully parsed only it contasion one of these;
And since your string has thousands seperator or decimal seperator (this depends on which one you used for) this method throws exception.
Instead of that, you can use Int32.Parse(String, NumberStyles, IFormatProvider)
overload which you can specify your NumberStyles
like NumberStyles.AllowDecimalPoint
or NumberStyles.AllowThousands
As an example;
string str = "1,000";
int ithou = Int32.Parse(str, NumberStyles.AllowThousands,
new CultureInfo("ko-KR"));
Console.WriteLine(ithou); // Prints 1000
If you want to get 1
as a result, you can use CultureInfo.Clone
method to your culture and set it's NumberDecimalSeparator
and NumberGroupSeparator
properties like;
string str = "1,000";
CultureInfo c = (CultureInfo)CultureInfo.GetCultureInfo("ko-KR").Clone();
c.NumberFormat.NumberDecimalSeparator = ",";
c.NumberFormat.NumberGroupSeparator = ".";
int dthou = Int32.Parse(str, NumberStyles.AllowDecimalPoint, c);
Console.WriteLine(dthou ); // Prints 1
I don't think it's a cultural problem. It is the inconsistent handling of the formatted string. ToDouble accepts strings with comma, but ToInt32 does not. It's like going back to the original question again, but couldn't ToInt32 be implemented to accept the comma just like ToDouble function?
Oh my dear friend, you are still thinking wrong..
Everything is a culture problem in your case. There is no such a thing "Convert.ToDouble()
accepts strings with comma, but Convert.ToInt32()
does not".
Let's look at one more time how these methods are implemented.
Convert.ToDouble(string)
uses Double.Parse(value, CultureInfo.CurrentCulture)
explicitly and it is implemented like;
public static double Parse(String s, IFormatProvider provider)
{
return Parse(s, NumberStyles.Float| NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider));
}
With this NumberStyles.Float| NumberStyles.AllowThousands
, you can use both decimal point or thousands separator in your code but ,
is your culture's NumberGroupSeparator
not NumberDecimalSeparator
. That's why your string will be parsed as a thousands seperetor. There is no such a thing Convert.ToDouble uses string with comma. It can be use your current culture's NumberDecimalSeparator
or NumberGroupSeparator
depends on which character your string has. If both were equal, NumberDecimalSeparator
will be dominant and it will be used.
Convert.ToInt32(string)
uses Int32.Parse(string, CultureInfo.CurrentCulture)
explicitly and it's implemented like;
public static int Parse(String s, IFormatProvider provider)
{
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider));
}
As I said before, NumberStyles.Integer
allows three things for your string; leading white space, trailing white space and leading positive or negative sign. It can't be parse if your string has decimal separator or thousands separator no matter it is comma or dot.
but couldn't ToInt32 be implemented to accept the comma just like ToDouble function?
I told you before. Convert.ToInt32
doesn't have an overload takes NumberStyles
as a parameter. You can use Int32.Parse(String, NumberStyles, IFormatProvider)
overload which you can specify your NumberStyles
enumeration for parsing your decimal separator or thousands separator.
Upvotes: 3
Reputation: 613013
For the double conversion, there are two possibilities:
,
is the number group separator. And so the conversion succeeds and returns a value of 1000
.,
is used as the decimal separator. Again the conversion to floating point succeeds but this time returns 1
.For conversion to integer, "1,000"
is simply not an integer. My suspicion, given your naming, is that ,
is a number group separator for you. And you are expecting it to be treated that way by ToInt32()
. But ToInt32()
does not accept number group separators. Valid characters for ToInt32()
are 0
to 9
, the optional sign prefix of -
or +
and leading or trailing whitespace.
Upvotes: 4
Reputation: 3554
In the english culture the decimal sign is "." . In the swedish culture the decimal sigh is ",". The myriad sign can be " ", "," or ".". So that's why C# throws an exception when the decimal sign is different than its culture specified.
Upvotes: 0