8

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

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

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

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

小数点:

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

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

让我从我上个月遇到的所有问题中给你一些。

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

    /// <summary>
    /// Loads animation setting from xml file.
    /// </summary>
    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抛出异常,一个简单的方法是使用XmlConvert.ToDouble();或解析InvariantCulture.

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

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

那么我们该如何解决这个问题呢?

  • 修复代码中的错误 - 只能使用可用的源代码并且很乏味。
  • 更改数据(CVS、XML 等)——即使有可能,但对更改数据不太满意。
  • 更改操作系统默认的小数点分隔符 - 不会发生。

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

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

4

5 回答 5

6

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

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

于 2011-06-21T16:26:21.780 回答
1

在我看来,方法应该如下:

  1. 在内部存储中,数字只是数字。所以不会出现问题。
  2. 在解析输入文本源时,您应该根据创建源的语言环境来解析它们——很可能是不变的文化
  3. 将值输出给用户时,根据用户首选的语言环境对其进行格式化。在 C# 中,这意味着维护CurrentCulture(不是CurrentUICulture,请参阅此处为什么)。

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

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

于 2011-06-21T16:29:57.993 回答
1

我感觉到你的痛苦,Windows Phone 7 的 RunKeeper 端口出错了,并报告我上个月打破了光速 100 000 倍。

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

我相信许多 .NET 开发人员遇到的问题是,他们不明白所有默认的解析方法都回退到Thread.CurrentThread.CurrentCulture该文化并使用特定的数字格式,日期和时区也是如此。

我可能会考虑做的事情是建立一个责任链,其中我首先查询特定文化的变体和文化不变的后备。我永远不会混合使用这些,但如果您遵守一些典型的约定(例如英语数字格式),我会支持文化不可知的默认设置。但这可能不是每次都正确的选择,请教育您的用户,如果他们认为解析混合数字格式的 CSV 文件是正确的做法。

于 2011-06-21T16:37:32.740 回答
1

这里没有灵丹妙药。

一些建议:

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

看这里:

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

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

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

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

肯定有一些陷阱需要提防。

于 2011-06-21T17:00:13.330 回答
1

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

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

现在,我知道这听起来需要做很多工作,但这只是需要做的事情。您可能只想感谢 Microsoft 中的某个可怜的灵魂,他/她出于善意决定最终用户的 CurrentCulture 是格式化提供程序的最佳默认设置......显然,过去这样做的其他框架设计者是错误的,来自MS是对的,哈?由于这个愚蠢的、无法修复的错误,大量现金蒸发了。

于 2011-06-21T17:03:25.143 回答