无效的 CultureInfo 不再抛出 CultureNotFoundException

本文关键字:CultureNotFoundException 不再 CultureInfo 无效 | 更新日期: 2023-09-27 18:32:25

使用 es-CA 创建区域性信息,这显然是不正确的,应该会引发异常,但不再如此。

之前抛出了一个CultureNotFoundExceptionnew CultureInfo("es-CA")。它现在似乎回退到es"未知区域设置"。虽然,做像xy-ZZ这样的事情也有效,这很奇怪?

为什么这不再引发异常?这在最新版本的 .NET 中是否发生了更改?

更新 1

该文档提到了以下内容:

如果操作系统不支持该区域性,并且名称不是补充区域性或替换区域性的名称,则该方法将引发 CultureNotFoundException 异常。

在 Windows 7 上对此进行测试,它会抛出CultureNotFoundException但在 Windows 10 上不会抛出异常。

无效的 CultureInfo 不再抛出 CultureNotFoundException

现在根据

注释添加答案。

由于 Windows 设计中的更改,如果名称与 BCP-47 匹配,现在不再有"无效区域性",因此 .NET Framework/.NET Core 不会引发异常,而是接受新的区域性。

您可以参考 GitHub 讨论,以及下面的引用,

由于框架依赖于操作系统来获取区域性,因此操作系统的 正在移动到模型,任何 BCP-47 区域性名称都变得有效,即使 操作系统不支持它。例如,Windows 10支持任何 格式良好的区域名称,即使操作系统也没有此类的真实数据 文化。例如,如果尝试在 视窗 10 它会成功。考虑到这一点,没有意义 具有区域性枚举,因为我们返回的任何集合并不意味着这些是 唯一支持的区域性。查看您的问题,您的解决方法是 可以接受。如果真的想有更好的方法,我们可以考虑 类似于CultureInfo.TryGetCulture(),但正如我之前所说 向前发展,几乎任何文化都是有效的。

我发布这个作为对OP问题帖子中几乎提出的两个问题的答案:

在 Windows 10 的重大更改以支持BCP-47之后......

  1. 如何判断给定的CultureInfo对象是"真正的"文化,还是在代码中从头开始创建的虚假/人为/私有CultureInfo
  2. 如何判断用户提供的 String cultureName 值是否对new CultureInfo(String)有效,以及运行时环境(.NET 和/或 OS)是否具有该名称的有意义的区域性数据(不仅仅是DisplayName)?
<小时 />

问题 1:验证给定的CultureInfo实例:

根据 CultureTypes 的文档,在 Windows 10 之前,如果 CultureInfo.CultureTypes 属性具有标志UserCustomCulture则它是自定义区域性。从 Windows 10 开始,UserCustomCulture标志指示自定义区域性,但也指示"不受完整区域性数据集支持且没有唯一本地标识符的系统区域性"。

因此,如果您想在 Windows 10 上验证CultureInfo,就像在 Windows 8.1 或更早版本上一样,只需检查:

  1. CultureInfo.CultureTypes没有设置CultureTypes.UserCustomCulture标志。
  2. 如果确实UserCustomCulture,请确保CultureInfo.ThreeLetterWindowsLanguageName != "ZZZ"
    • "ZZZ"魔术字符串似乎在Windows本身中,并且仅在Windows 10或更高版本上出现。
    • .NET Core自己的测试用例包括对它的测试,但除了注释".GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */;"之外,从未解释过它。

所以这对我有用:

public static Boolean ValidateCultureInfoWithPreWindows10Logic( CultureInfo ci )
{
    Boolean hasUserCustom = ( ci.CultureTypes & CultureTypes.UserCustomCulture ) == CultureTypes.UserCustomCulture;
    if( hasUserCustom )
    {
        if( ci.ThreeLetterWindowsLanguageName == "ZZZ" )
        {
            // Windows doesn't have a name for this language - this CultureInfo is invalid under Windows 8.1 or earlier.
            return false;
        }
        else
        {
            // The `UserCustomCulture` flag means *some* CultureData is missing, but not enough to make them useless.
            // On both Win8 and Win10, the same 8 Neutral Cultures match here: [ jv, jv-Latn, mg, nqo, sn, sn-Latn, zgh, zgh-Tfng ]
            return true;
        }
    }
    else
    {
        // The `UserCustomCulture` flag is not set, which means 100% of the CultureInfo's CultureData exists in the system.
        return true;
    }
}

问题 2:验证给定String cultureName

  • 请记住,区域性名称是分层的,有 3 个主要级别:

    • Invariant = CultureInfo.InvariantCulture .
    • Neutral = 没有区域的语言名称,例如 enfr
    • Specific = 特定地区的语言名称,例如 en-USen-GBfr-CAfr-FR
    • 此外,还有一些
    • 用于子特定区域的名称,例如 ca-ES-valencia .不过,我从未遇到过超过 3 个级别的深度。
  • 验证cultureName取决于您的业务/域/应用程序要求:

    • 如果要要求名称与操作系统已知的语言区域匹配,则只需执行ValidateCultureInfoWithPreWindows10Logic( new CultureInfo( cultureName ) )即可(当然,在验证cultureName格式是否符合 BCP-47 之后)。
    • 如果要要求名称与操作系统已知的语言匹配,但允许指定任何操作系统已知的区域,即使操作系统没有特定的文化数据(例如,使用 CultureInfo.CreateSpecificCulture("en-FR") 时),则检查ci.ThreeLetterWindowsLanguageName != "ZZZ"就足够了。
    • 如果要要求名称与操作系统已知的语言匹配,但允许指定任何区域,即使操作系统甚至不知道该区域,那么这很复杂......

下表显示了 Windows 10 与 Server 2012 R2 以及 .NET 4.8 与 .NET 6 上的 new CultureInfoCultureInfo.CreateSpecificCulture 的结果:

表达视窗 10 + .NET 6视窗 10 + .NET 4.8视窗 2012 R2 + .NET 4.8
CultureInfo ci1 = new CultureInfo("en-FR")
CI1.显示名称"英语(法国)""未知区域设置 (en-FR)" CultureNotFoundException
CI1.三字母窗口语言名称"噗嗤""埃努" CultureNotFoundException
CI1.文化类型特定文化 |用户自定义文化 |已安装 Win32文化特定文化 |用户自定义文化 CultureNotFoundException
CultureInfo spec = CultureInfo.CreateSpecificCulture("en-FR")
规范。显示名称"英语(法国)""未知区域设置 (en-FR)""英语(美国)"
规范。三字母窗口语言名称"噗嗤""埃努""埃努"
规范。文化类型特定文化 |用户自定义文化 |已安装 Win32文化特定文化 |用户自定义文化特定文化 |已安装的 Win32 文化 |框架文化
相关文章:
  • 没有找到相关文章