如何修复小数分隔符有问题的应用程序

这篇文章是关于C#和.Net的,但有些信息对其他技术很有价值。

因为我记得,因为解析十进制数字的风格不同,我一直遇到崩溃的应用程序或游戏问题。 它经常发生,从CAD应用程序,库到网页。 我不确定这是无知还是缺乏知识,但它真的很烦人。

有什么问题? 这是一篇关于它的维基文章,但它很简短:

这是一张地图,显示世界各地使用的小数点分隔符(十进制标记)。 不同的小数分隔符的地图

小数标记:

  • 期间 – 蓝色
  • 逗号 – 绿色
  • 非西方阿拉伯数字 – 红色
  • 未知 – 灰色

大多数欧洲,南美洲写1 000 000,00或1000000,00有时1.000.000,00与“帝国”相反(标记为蓝色)写入1,000,000.00

让我来谈谈我上个月遇到的所有问题。

  1. 网页上的数字难以阅读:让我们看一下观看次数最多的YTvideo 。 它向我展示了390159851.超过一百万的数字很难读,数量级是多少? 是39毫升还是390?
  2. 适用于Windows Phone 7的 Mirosoft XNA示例 :有一个非常简洁的类可解析XML文件以生成XNA动画

    ///  /// Loads animation setting from xml file. ///  private void LoadAnimiationFromXML() { XDocument doc = XDocument.Load("Content/Textures/AnimationsDefinition.xml"); XName name = XName.Get("Definition"); var definitions = doc.Document.Descendants(name); if (animationDefinition.Attribute("Speed") != null) { animation.SetFrameInvterval(TimeSpan.FromMilliseconds( double.Parse(animationDefinition.Attribute("Speed").Value))); } 

    double.Parse抛出一个exception,一个简单的灵魂就是使用XmlConvert.ToDouble(); 或使用InvariantCulture解析。

  3. 使用CSV文件将输入向量存储为CSV的.Net应用程序 – 也会抛出。

  4. 另一个在类中有一些解析的.Net应用程序 – 抛出。

那我们怎么解决这个问题呢?

  • 修复代码中的错误 – 只能使用可用的源代码并且繁琐。
  • 更改数据(CVS,XML等) – 即使有可能,也不会对改变数据感到满意。
  • 更改操作系统默认小数分隔符 – 不会发生。

还有其他方法来解决这个问题吗? 我可以让应用程序保持不变吗? 就像在不同的环境中启动应用程序一样。

PS。 我想运行该应用程序,但我没有代码。

正确设置Thread.CurrentThread.CurrentCulture ,你不会遇到这样的问题。 在这里阅读如何编写与文化无关的代码。

编辑:如果您无权访问代码,则可以在具有预期文化集的用户帐户下运行该应用程序。 为了快速访问,您可以创建一个英语用户,一个德国用户,一个法国用户..

在我看来,方法应该遵循:

  1. 在内部存储中,数字只是数字。 所以没有问题发生。
  2. 在解析输入文本源时,您应该根据创建源的区域设置来解析它们 – 最可能的是,不变的文化
  3. 将值输出给用户时,请根据用户首选的语言环境对其进行格式化。 在C#中,这意味着维护CurrentCulture (不是CurrentUICulture ,请参见此处原因)。

这应该相对简单并涵盖所有情况。

这一切都适用于是应用程序作者的情况。 对于其他人的应用程序,各自的开发人员必须自己修复他们的错误。

我觉得你的痛苦,RunKeeper到Windows Phone 7的端口出错了,据报道我上个月打破了光速,减少了10万。

如果你是马虎,你会遇到这些问题,但在大多数情况下,他们可以避免。 严格来说,您应始终以其本地化格式显示信息,然后在保存时将其转换为与文化无关或基本值。 这样您就可以始终瞄准特定的文化。

我相信许多.NET开发人员遇到的问题是,他们不理解所有默认的解析方法都会回Thread.CurrentThread.CurrentCulture上,并且对该文化使用特定的数字格式,并且它与日期和时区相同。

我可能会考虑做的事情是建立一个责任链,其中我首先查询了特定于文化的变体,以及文化不变的后备。 我永远不会混合这些,但我支持文化无关的默认,如果你遵守一些典型的约定(例如英文数字格式)应该有效。 但这可能不是每次都是正确的选择,如果他们认为解析混合数字格式的CSV文件是一件好事,那么请教育用户。

这里没有银弹。

一些建议:

处理存储在配置文件中的内部数据时,可以使用不变文化。 这样,无论机器是什么文化,您都可以以一致的方式读取和编写自己的内部数据。

看这里:

http://msdn.microsoft.com/en-us/library/4c5zdc6a.aspx

其他问题处理简单的事情如string.ToLower()。

看起来很无辜,直到你尝试小写英文字母而不是当前文化中不存在的字母。 (EG土耳其语)

在这些情况下,调用string.ToLower()应该替换为文化重载,并且应该传递当前文化或不变文化(取决于您的情况)。

肯定是值得注意的一些陷阱。

实际上没有其他方法可以解决此问题,只需在代码中修复它即可。
如果您想运行FxCop,您很快就会学会将有效的CultureInfo传递给每个可能的ToString()Parse()方法。 坦率地说,即使您知道默认使用CultureInfo.CurrentCulture ,也应该这样做。
通过始终通过IFormatProvider,您告诉其他开发人员:

  1. ToString(CultureInfo.CurrentCulture)Parse(whatever, CultureInfo.CurrentCulture) – 这是最终用户将看到或将能够进入的东西,所以我们需要关心他/她的文化背景。
  2. ToString(CultureInfo.InvariantCulture)Parse(whatever, CultureInfo.InvariantCulture) – 这是我们在内部使用的东西,并不打算向用户显示。

现在,我知道这听起来像很多工作,但这只是需要做的事情。 您可能只是想感谢微软中的一些可怜的灵魂,他/她的良好意图决定最终用户的CurrentCulture是格式化提供者的最佳默认值…显然,过去这样做的其他框架设计者是错误的并且来自MS是对的,哈? 由于这个愚蠢,无法修复的错误,大量现金已经消失。