如何修复小数分隔符有问题的应用程序
这篇文章是关于C#和.Net的,但有些信息对其他技术很有价值。
因为我记得,因为解析十进制数字的风格不同,我一直遇到崩溃的应用程序或游戏问题。 它经常发生,从CAD应用程序,库到网页。 我不确定这是无知还是缺乏知识,但它真的很烦人。
有什么问题? 这是一篇关于它的维基文章,但它很简短:
这是一张地图,显示世界各地使用的小数点分隔符(十进制标记)。
小数标记:
- 期间 – 蓝色
- 逗号 – 绿色
- 非西方阿拉伯数字 – 红色
- 未知 – 灰色
大多数欧洲,南美洲写1 000 000,00或1000000,00有时1.000.000,00与“帝国”相反(标记为蓝色)写入1,000,000.00
让我来谈谈我上个月遇到的所有问题。
- 网页上的数字难以阅读:让我们看一下观看次数最多的YTvideo 。 它向我展示了390159851.超过一百万的数字很难读,数量级是多少? 是39毫升还是390?
-
适用于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
解析。 -
使用CSV文件将输入向量存储为CSV的.Net应用程序 – 也会抛出。
-
另一个在类中有一些解析的.Net应用程序 – 抛出。
那我们怎么解决这个问题呢?
- 修复代码中的错误 – 只能使用可用的源代码并且繁琐。
- 更改数据(CVS,XML等) – 即使有可能,也不会对改变数据感到满意。
- 更改操作系统默认小数分隔符 – 不会发生。
还有其他方法来解决这个问题吗? 我可以让应用程序保持不变吗? 就像在不同的环境中启动应用程序一样。
PS。 我想运行该应用程序,但我没有代码。
正确设置Thread.CurrentThread.CurrentCulture
,你不会遇到这样的问题。 在这里阅读如何编写与文化无关的代码。
编辑:如果您无权访问代码,则可以在具有预期文化集的用户帐户下运行该应用程序。 为了快速访问,您可以创建一个英语用户,一个德国用户,一个法国用户..
在我看来,方法应该遵循:
- 在内部存储中,数字只是数字。 所以没有问题发生。
- 在解析输入文本源时,您应该根据创建源的区域设置来解析它们 – 最可能的是,不变的文化
- 将值输出给用户时,请根据用户首选的语言环境对其进行格式化。 在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,您告诉其他开发人员:
-
ToString(CultureInfo.CurrentCulture)
或Parse(whatever, CultureInfo.CurrentCulture)
– 这是最终用户将看到或将能够进入的东西,所以我们需要关心他/她的文化背景。 -
ToString(CultureInfo.InvariantCulture)
或Parse(whatever, CultureInfo.InvariantCulture)
– 这是我们在内部使用的东西,并不打算向用户显示。
现在,我知道这听起来像很多工作,但这只是需要做的事情。 您可能只是想感谢微软中的一些可怜的灵魂,他/她的良好意图决定最终用户的CurrentCulture是格式化提供者的最佳默认值…显然,过去这样做的其他框架设计者是错误的并且来自MS是对的,哈? 由于这个愚蠢,无法修复的错误,大量现金已经消失。