2014-04-23 125 views
5

我正在从旧的MFC GUI迁移到C#。用逗号将字符串转换为double和int是不同的。为什么?

我在构建基于窗体的GUI时,遇到意外的异常,将字符串转换为整数类型。我认为它会像转换字符串一样工作。

string str = "1,000"; 
double dthou = Convert.ToDouble(str); // OK 
int ithou = Convert.ToInt32(str);  // raises an exception 

转换为double会给出正确的值:1000.0。 对于int转换,我能够得到一个解决方案:Convert.ToInt32() a string with Commas

但我很好奇,如果有任何理由背后。 或者我错过了什么?

我能找到一个类似的,但不完全是一个重复的问题:学习有关的文化问题后 Number parsing weirdness

[编辑]。

我处于一种文化冲击之中,因为到目前为止,在韩国,浮点数和整数都用“,”表示为数千个组和“。”。为小数点(至少在现实世界中,在韩国,我的意思是,我认为...)。 我想我将不得不接受MS Visual Studio的当前设置并继续。

[EDIT2]沉睡在这个问题之后。

我认为它更多的格式化字符串处理不一致。 ToDouble接受带有千位分隔符的字符串(在我的文化中,逗号),但ToInt32不。如果ToDoublefloat | allowThousands,那么为什么不能ToInt32已被integer | allowThousands正是我所要求的。

+8

您目前的文化是什么? –

+1

这似乎是一个文化问题。 – Flater

+0

CultureInfo.CurrentCulture.Name告诉我“ko-KR” – Keugyeol

回答

3

对于双转换,有两种可能性:

  1. 在你的文化,,是数字组分隔符。转换成功并返回值为1000
  2. 或者,在您的文化中,,用作小数点分隔符。再次转换为浮点成功,但这次返回1

对于转换为整数,"1,000"根本不是一个整数。鉴于你的命名,我的怀疑是,是你的一个数字组分隔符。而且你期望它可以通过ToInt32()这样处理。但ToInt32()不接受号码组分隔符。 ToInt32()的有效字符是09,可选的符号前缀-+以及前导或尾随空格。

+0

用我的文化“ko-KR”意思是韩语,转换为double可以给出正确的值,在这种情况下为1000.0; – Keugyeol

+1

这取决于你的意思是正确的。例如,在法国,正确答案是'1.0'。 –

+0

我编辑了评论以添加我的文化:“ko-KR”,谢谢。 – Keugyeol

0

在英文文化中,小数点是“。”。 。在瑞典文化中,小数叹息是“,”。无数的符号可以是“”,“”或“。”。所以这就是为什么当C#在小数点符号与指定区域不同时引发异常。

+0

据我所知,逗号在韩国的浮动和整数表达式中都是一样的,当其中一个转换抛出异常时,我意外地被捕获了。 – Keugyeol

2

在你的个人主页上,它说你来自韩国。这就是为什么我假设你现在的文化是ko-KR。 (和你said以及。)

而且它的NumberDecimalSeparator.但它的NumberGroupSeparator,

enter image description here

Convert.ToDouble作品和它假定你,是成千上万的分隔符,而不是小数分隔符。这就是为什么你的dthou将是1000而不是1

Convert.ToInt32(string)明确使用Int32.Parse(string, CultureInfo.CurrentCulture)并且这种方法implemented like;

public static int Parse(String s, IFormatProvider provider) 
{ 
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); 
} 

正如您所见,此方法使用NumberStyles.Integer作为默认值。这就是为什么你的字符串可以成功解析,只有它包含其中之一;

  • 开头的空白
  • 结尾的空白
  • 领先的符号(正或负)

而且,由于你的字符串有数以千计的分隔符或小数点分隔符(这取决于哪一个时使用的)这个方法抛出异常。

取而代之的是,你可以用它Int32.Parse(String, NumberStyles, IFormatProvider) overload可以指定你的NumberStylesNumberStyles.AllowDecimalPointNumberStyles.AllowThousands

作为一个例子;

string str = "1,000"; 
int ithou = Int32.Parse(str, NumberStyles.AllowThousands, 
         new CultureInfo("ko-KR")); 
Console.WriteLine(ithou); // Prints 1000 

如果你想获得1结果,你可以使用CultureInfo.Clone method到你的文化,并设置它的NumberDecimalSeparatorNumberGroupSeparator性能喜欢;

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 

我不认为这是一个文化问题。这是格式化字符串的不一致处理 。 ToDouble用逗号接受字符串,但 ToInt32不。这就像回到原来的问题, ,但不能ToInt32接受逗号,就像 ToDouble函数?

哦,我亲爱的朋友,你还在想错了..

一切都在你的情况下,一个文化问题。没有这样的事情“Convert.ToDouble()接受逗号字符串,但Convert.ToInt32()”。

让我们再来看看这些方法是如何实现的。

Convert.ToDouble(string)明确使用Double.Parse(value, CultureInfo.CurrentCulture)并且它是implemented like;

public static double Parse(String s, IFormatProvider provider) 
{ 
    return Parse(s, NumberStyles.Float| NumberStyles.AllowThousands, NumberFormatInfo.GetInstance(provider)); 
} 

有了这个NumberStyles.Float| NumberStyles.AllowThousands,你可以在你的代码中使用两个小数点或千位分隔符,但,是你的文化的NumberGroupSeparator没有NumberDecimalSeparator。这就是为什么你的字符串将被解析为千位分隔符。 没有这样的事情Convert.ToDouble使用逗号的字符串。它可以使用您当前的文化的NumberDecimalSeparatorNumberGroupSeparator取决于您的字符串具有哪个字符。如果两者相等,NumberDecimalSeparator将占主导地位并将被使用。

Convert.ToInt32(string)明确使用Int32.Parse(string, CultureInfo.CurrentCulture)并且它是implemented like;

public static int Parse(String s, IFormatProvider provider) 
{ 
    return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.GetInstance(provider)); 
} 

正如我之前所说,NumberStyles.Integer允许你的字符串有三样东西;领先的白色空间,尾随的白色空间和领先的积极或消极的迹象。无论是逗号还是点号,您的字符串都有小数点分隔符或千位分隔符不能解析。

但不能ToInt32被实现为接受逗号,就像 ToDouble函数?

我以前告诉过你。 Convert.ToInt32没有过载需要NumberStyles作为参数。您可以使用Int32.Parse(String, NumberStyles, IFormatProvider) overload,您可以指定NumberStyles枚举来解析您的小数点分隔符或千位分隔符。

+0

感谢您的详细描述。知道了ToInt32()的内部工作之后,我想知道它是否可以是NumberStyles.AllowThousands,而不是ParseInt32函数参数中的NumberStyles.Integer。 – Keugyeol

+1

@ Keegyeol更新了我的答案。看一眼。如果你在不改变文化的情况下使用了'NumberStyles.AllowThousands',它将被解析为千位分隔符,结果将为'1000'。如果您想克隆自己的文化并将其设置为NumberDecimalSeparator和NumberGroupSeparator,那么您可以通过枚举NumberStyles.AllowDecimalPoint来获得结果1。 –

+0

@Downvoter至少要留心评论,以便我可以看到我可能会出错的地方? –