【问题标题】:ToString("0") versus ToString(CultureInfo.InvariantCulture)ToString("0") 与 ToString(CultureInfo.InvariantCulture)
【发布时间】:2010-12-02 00:47:01
【问题描述】:

我想确保我的应用程序中的某些数字在打印时没有任何分隔符、分组等,无论当前环境如何。似乎以下两种方法产生相同的结果(可能更多):

123456789.ToString("0");
123456789.ToString(CultureInfo.InvariantCulture);

您是否知道任何极端情况或怪癖?哪个更“正确”?你会用哪一个?

我以前用第二个,最近发现第一个开始用了,因为不需要额外的using System.Globalization

【问题讨论】:

    标签: .net globalization cultureinfo


    【解决方案1】:

    根据此处的答案和讨论,我进行了更多调查。这是我发现的:

    • 当您使用不带任何参数的12345678.ToString() 时,.NET 使用一般的通用格式说明符“G”,它仅受 NumberFormatInfo.NegativeSign、NumberFormatInfo 的影响。 NumberDecimalSeparator、NumberFormatInfo.NumberDecimalDigits 和 NumberFormatInfo.PositiveSign。对我来说,这意味着在任何文化中12345678.ToString() 应该始终产生“12345678”。

    • 如果要分隔数字,则需要使用数字格式说明符“N”(或者,当然,提供自定义格式字符串)。数字分组也适用于“C”和“P”。

    • 不变的文化确实指定了数字分组(当然是3位数字)和数字分隔符。所以123456789.ToString(CultureInfo.InvariantCulture) 产生“123456789”的原因不是因为文化不变,而是因为默认的通用数字格式说明符“G”。

    所以我会说结论是完全可以不用担心任何额外的参数只需使用

    12345678.ToString()
    

    我认为这是所有情况中最好的,因为这意味着通常您甚至不需要调用ToString(),因为大多数打印/写入函数都接受各种参数并为您执行ToString()

    【讨论】:

      【解决方案2】:

      这两种方法是不等价的:第一种是使用CurrentCulture。这可能会导致在某些文化中出现额外的点/逗号(我没有示例)。

      当您使用InvariantCulture 时,您可以确定始终使用相同的格式。

      编辑:而且,如果您使用 CodeAnalysis,当您不使用 CultureInfo 时会报错。

      【讨论】:

      • 我通过修改当前线程文化测试了第一个,并没有影响它。我认为“0”意味着:至少一位数字+没有数字分组或分隔符。如果我想要一些数字分组或分隔符,我想我必须做类似“000,000”的事情。
      • 但你是对的:InvariantCulture“听起来”更明确。甚至 MSDN 也说“......它与英语相关,但与任何国家/地区无关”。嗯,当我想到更多时,ToString(CultureInfo.InvariantCulture),它意味着如果使用“G”格式化的数字。这一切只是碰巧起作用,因为“G”似乎没有使用任何分组。但是(我只是查了一下)不变的文化有一些指定的分组。例如,尝试 12345789.ToString("N", CultureInfo.InvariantCulture)。
      【解决方案3】:

      (约 5 年后...)

      我正在查找这个确切的问题,但由于没有公认的答案,即使 Jan Zich 是正确的,我想我还是会整理一个小例子来测试这个。

      到目前为止,我还要说 .ToString()、.ToString("0") 和 .ToString(Any Culture Info) 之间没有区别(就整数和小数而言)

      var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures)
          .Except(CultureInfo.GetCultures(CultureTypes.SpecificCultures));
      
      foreach(var c in cultures){
          var num = (int.MinValue);/*
          var num = (int.MaxValue);/*
          var num = (decimal.MinValue);/*
          var num = (decimal.MaxValue);/*
      --*/
      
          var s1 = num.ToString("0") ;
          var s2 = num.ToString(c);
          if(s1 != s2){
              var s = string.Format("{2}:  {0}    {1}",s1,s2,c);
              s.Dump();
          }
      }
      

      LinqPad snippet

      【讨论】:

        【解决方案4】:

        .ToString().ToString(CultureInfo.InvariantCulture) 似乎对整数给出了相同的结果。

        下面的代码在我的 PC 上给出了“809 个文化测试,发现 0 个差异”的结果(对于 .NET Framework 4.7.2):

        var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures).ToArray();
        var numbers = new[] { 0, -1, 1, int.MinValue, int.MaxValue };
        
        var diffsFound = 0;
        foreach (var culture in cultures)
        {
            foreach (var number in numbers)
            {
                var s1 = number.ToString();
                var s2 = number.ToString(culture);
                if (s1 != s2)
                {
                    Console.WriteLine($"{culture.DisplayName}: {s1} != {s2}");
                    diffsFound++;
                }
            }
        }
        
        Console.WriteLine($"{cultures.Length} cultures tested, {diffsFound} differences found.");
        

        【讨论】:

        • 当我在 DotNetFiddle 上运行此代码时,我发现了 178 个差异,使用 .NET Core 3.1:dotnetfiddle.net/ta2jvd733 cultures tested, 178 differences found.FZF
        【解决方案5】:

        如我所见,第一个格式是使用计算机默认区域性至少包含一个字符的数字。 第二个将根据 InvariantCulture 规则将其格式化为数字。

        鲍比

        【讨论】:

        • 如果我错了,请纠正我:我认为没有数字分组、分隔符等适用于 123456789.ToString("0")?
        • 呃……真的没有。我把它误认为是像“N0”这样的格式符号,它确实应用了当前的文化规则。你是对的,因为 0 是直接格式,它不应用 any 文化信息。不过,也有人可以使用 123456789.ToString(); .
        【解决方案6】:

        2 行做不同的事情。第一行使用本地文化格式化数字,第二行将其转换为字符串而不进行格式化但使用 CultureInfo.InvariantCulture。

        您将 CultureInfo.InvariantCulture 与此类方法(ToString、ToLower ...)一起使用,以确保当任何软件(数据库、另一个库 ...)使用该值时,无论其文化是什么,它将产生相同的值,当他们可以获取该值时,他们可以继续处理它。但是,如果您不使用此软件,则其他软件必须弄清楚您的文化是什么。你的意思是用逗号还是其他什么的小数分隔符...?

        当您想在库、数据库之间交换/使用值并使用 CultureInfo.CurrentCulture 向应用程序的用户展示时,所有和所有都使用 CultureInfo.InvariantCulture。

        // for softwares
        string mystring1 = 1234.ToString("0", CultureInfo.InvariantCulture);
        
        // for your application users
        string mystring2 = 1234.ToString("0", CultureInfo.CurrentCulture);
        

        【讨论】:

          【解决方案7】:

          如果您想确保指定“无格式,无论如何”,我个人认为您拥有的第一个选项:

          123456789.ToString("0");
          

          更好地传达意图。不利的一面是,如果文化覆盖了您正在使用的数字类型的格式字符串“0”。

          【讨论】:

          • 哦,我现在才知道您可以覆盖格式字符串?我需要查一下。
          • 你确定超载了吗? MSDN (msdn.microsoft.com/en-us/library/dwhawy9k.aspx) 说:“任何其他单个字符 [除了这些标准之一] 在运行时都会引发 FormatException。”
          • 我不确定是不是这样。我看到快速访问 MSDN 库会告诉我:)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多