C# .NET Double.TryParse(num、format、cultureinfo、out)错误

C# .NET Double.TryParse(num、format、cultureinfo、out)错误,c#,.net,vb.net,internationalization,double,C#,.net,Vb.net,Internationalization,Double,背景:我最近有幸编写了一些代码,这些代码需要可靠地将字符串转换为双精度字符串。该功能也必须分发。i、 e.字符串存储在数据库中,需要在跨不同地区运行的多个代理上转换为数字。由于限制的原因,更改数据库模式是不可能的,我必须在遗留代码库中完成这项工作,并提供简单的升级路径,同时不破坏现有功能 我能够通过将存储的字符串规范化为不变格式并向编码中添加一个标志来解决这个问题,以指示值是规范化的,应该采用新路径还是非规范化(sp?)并采用传统路径 我忘了提到原始值是由最终用户输入的,必须在可接受的格式范围内

背景:我最近有幸编写了一些代码,这些代码需要可靠地将字符串转换为双精度字符串。该功能也必须分发。i、 e.字符串存储在数据库中,需要在跨不同地区运行的多个代理上转换为数字。由于限制的原因,更改数据库模式是不可能的,我必须在遗留代码库中完成这项工作,并提供简单的升级路径,同时不破坏现有功能

我能够通过将存储的字符串规范化为不变格式并向编码中添加一个标志来解决这个问题,以指示值是规范化的,应该采用新路径还是非规范化(sp?)并采用传统路径

我忘了提到原始值是由最终用户输入的,必须在可接受的格式范围内。这意味着存储值可能有数字分组说明符,也可能没有数字分组说明符。显然,这是危险的,目前只针对beta版,而且很快就会对UI进行适当的国际化,以便发布适当的版本

也就是说,我认为我的转换代码应该能够处理数字分组字符是合理的,即使最终的规范化表单不包含它们。如果提供了正确的区域性格式,则Double.TryParse()和Double.ToString()在处理此问题时应该没有问题,并且转换代码可能会因为其他原因(是遗留代码!)而被重用

是.NET错误,因此我认为围绕国际化字符串到双精度转换代码编写一些单元测试是个好主意

我编写了两个主要测试(psuedo代码)

测试1:

Double testValue = 15000.05
foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures) 
{
    string testString = testValue.ToString(ci);
    Assert.AreEqual(testValue, Convert(testString, ci));
}
测试2:

foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures) 
{
    string testString = testValue.ToString("N2", ci);
    Assert.AreEqual(testValue, Convert(testString, ci));
}
相关转换代码(几乎一行一行):

对于测试,收集所有区域性代码的确切方法可能不同,Convert的方法签名不同,周围的代码和assert略有不同。 相关部分是.ToString(ci)和.ToString(“N2”,ci)。 对于en US,这些to版本将分别生成“15000.05”和“15000.05”。 此外,此代码在.NET版本2.0-4.5.2下运行,我们在各种相关版本下运行测试。它的行为在所有方面都是相同的(*可能需要再次检查,但这肯定是.NET 4.5.2中的行为)

测试1通过

Test2在以下5个区域性代码上失败:

  • prs
  • prs AF
  • tzm
  • tzm板条
  • tzm Latn DZ
我们目前正在忽略这些不受支持的故障,并跟踪是否有我们关心的新故障出现

诊断 在对一些问题进行深入研究和实验之后,我们将问题追溯到数字分组说明符。i、 e.第千位分隔符。 将Double.TryParse()更改为

工作。因此,问题特别是Double.TryParse()的问题,可能与NumberStyle.Any说明符有关。或者,使用十六进制说明符对其进行加密也不起作用

因此,在.NET中,您可以使用特定的IFormatProvider将double转换为字符串,然后尝试使用相同的IFormatProvider将其转换回double,但会失败

问题:有人能解释为什么会发生这种情况吗

运行理论:我目前的两个想法是一个字符编码错误,带有数字分组字符或那些特定文化背景下的实际双重表示是不同的(类似于double x=0.3在.NET中实际上是0.299…)


免责声明:我在VB.NET和C#之间切换,因此请原谅任何语法混淆。另外,我知道这个测试没有正确地解释“奇数”数字分组,就像印地语中1015000是10,15000。以下是他写的:

“这里的问题是失败的文化,因为你有以下几点:

小数点分隔符为“,” 组分隔符为“” 货币小数点分隔符为“” 货币组分隔符为“,” 请注意,十进制分隔符与货币组分隔符相同。此外,组分隔符与货币十进制分隔符相同

现在,当您使用这种区域性设置数字格式时,您将得到字符串“15.000,05”。当您试图解析它时,您传递的是NumberStyles。Any表示该字符串可以是货币数字,也可以是十进制数字。这会使解析器在尝试解析字符时感到困惑。”。“因为它可以被视为货币十进制分隔符,也可以被视为组分隔符。解析器决定将其视为货币小数分隔符。然后解析器将继续运行,直到点击“,”并再次将其视为货币组分隔符。由于组分隔符不能位于十进制分隔符之后,解析器将无法解析字符串,并将从TryParse返回false(或从parse抛出异常)

要解决此问题,请从传递的NumberStyles中删除货币解析。i、 e

        Double.TryParse(numString, NumberStyles.Any & (~NumberStyles.AllowCurrencySymbol), ci, out numParsed);

我将结束这一问题,但如果您有任何问题,请随时回答。”

尚未进行进一步诊断,但我刚刚在dotnet github回购协议上提交了一个问题:
numOut = Double.Parse(numIn, ci)
        Double.TryParse(numString, NumberStyles.Any & (~NumberStyles.AllowCurrencySymbol), ci, out numParsed);