0

我正在使用一个 .Net Core 6 库 (dll),其中除其他功能外,数字和日期/时间信息以字符串形式输出,并且此代码需要全球化,即。要有文化意识。图书馆是一个文档生成系统,所以在同一个应用程序会话中,用户会为 de-CH、de-FR、en-US 等生成文档。所以基本上,我们希望图书馆具有文化意识,但是输出的文化应该具有“标准”格式,而不是在操作系统级别或用户级别定制的格式。

例如对于十进制值,库代码使用这些方法来输出内容:

public string ToString();
public string ToString(string? format);
public string ToString(IFormatProvider? provider)
public string ToString(string? format, IFormatProvider? provider)

因此,不同用户在具有不同区域性设置的不同计算机中调用这些重载,将以不同方式格式化输出:小数分隔符可以是逗号或点,而千位分组分隔符可能是非制动空格或 ' 等。

但是,当provider使用特定文化的实例显式传递参数时,例如“fr-CH”(瑞士-法语)和 CultureInfo.UseUserOverride == false,我期待始终相同的输出字符串,独立于用户和/或电脑。所以,我在想,.Net 对于所有文化类型的 CultureInfo-instances 的所有属性都有“内置”值,并且通过参数useUserOverride: false我可以强制格式化使用这些“内置”值,因此会输出总是相同的字符串。

但这似乎并非如此!

编码:

CultureInfo cultInfo = new CultureInfo(name: "fr-CH", useUserOverride: false)       //* fr-CH" is Swiss-French
Decimal myDec = -123456789123456.987654321M; 
String output = myDec.ToString(format: "N4", provider: cultInfo);       // I was expecting always same output independent, which user is calling it in which computer, but this is not the case!

此示例代码是使用 .Net Core 6 作为控制台应用程序编译的,我在 a) Windows 10 Pro PC 和 b) Windows Server 2012R2 上运行它,它们具有不同的输出。

  • 法国-CH/Windows Pro 10 PC:-123 456 789 123 456,9877
  • 法国-CH/Windows Server 2012R2:-123'456'789'123'456.9877

通过设置相同CultureInfo cultInfo = CultureInfo.InvariantCulture:然后结果看起来总是相同的,这是预期的。

我也尝试设置Thread.CurrentThread.CurrentCultureThread.CurrentThread.CurrentUICulture使用cultInfo上面的 -variable 然后调用ToString(format?, provider?),但没有效果:结果与没有设置CurrentThread. PS。我实际上从这里这里这里了解到,设置Thread.CurrentThread.CurrentUICulture与格式无关(我的情况),而是与翻译(resx 的东西)有关。

我知道有关-class的大量 Microsoft 文档CultureInfo,但我无法从那里的森林中看到树。

我的问题如下:

  • 任何版本的 .Net Core(或任何版本的 .Net Framework)是否有所有 CultureInfo 属性的“内置值”?
  • 我怎么能强制我的代码始终完全使用与环境无关的文化给定的文化?

这对于能够以可靠的方式对库输出进行单元测试非常重要。

这可能很重要,当读回(使用 System.Convert(value, provider?) 任何用户在任何计算机上输出的值时(只知道它们输出的文化)。

4

2 回答 2

0

您可以设置自定义文化并根据需要对其进行配置。

从现有的中性文件开始,例如InvariantCulture.
进行克隆以保持InvariantCulture原样。

var clone = CultureInfo.InvariantCulture.Clone() as CultureInfo;

然后对该克隆进行所需的更改 - 例如:

clone.NumberFormat.NumberDecimalSeparator = ",";
clone.NumberFormat.NumberGroupSeparator = ".";

可选但可取的是,您可能想要制作它的只读版本。

var customCulture = CultureInfo.ReadOnly(clone);

在需要固定受控输出的任何地方使用该文化 - 例如:

var number = -123456789123456.987654321M;
var formattedNumber = number.ToString("N4", customCulture)); // -123.456.789.123.456,9877

string将格式化版本解析回时应用相同的文化decimal- 例如:

var parsedNumber = decimal.Parse(formattedNumber, customCulture);

如果您对如何CultureInfo设置 a 感兴趣,请查看源代码
简而言之,InvariantCulture它具有固定设置,而其他则依赖于操作系统和可选的用户覆盖。

文档中:

.NET 从多种来源之一派生其文化数据,具体取决于实现、平台和版本:

  • 在 .NET Framework 3.5 和更早版本中,文化数据由 Windows 操作系统和 .NET Framework 提供。

  • 在 .NET Framework 4 及更高版本中,文化数据由 Windows 操作系统提供。

  • 在 Windows 上运行的所有 .NET Core 版本中,文化数据均由 Windows 操作系统提供。

因此,在特定 .NET 实现、平台或版本上可用的文化可能在不同的 .NET 实现、平台或版本上不可用。

一些 CultureInfo 对象因底层平台而异。

于 2021-12-22T19:31:22.220 回答
-1

将其设置在头上以使其正常工作,如果您不希望它在每个地方重复:

CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("fr-CH");
.....
Decimal myDec = -123456789123456.987654321M;
String output = myDec.ToString(format: "N4");
Console.WriteLine(output);

当您在其他计算机上运行代码时,请尝试检查cultureinfo 并查看它会返回什么。我敢打赌它没有将其设置为 fr-CH:

CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
        Console.WriteLine(currentCulture.Name);
于 2021-12-21T19:09:46.127 回答