无效的 CultureInfo 不再抛出 CultureNotFoundException
本文关键字:CultureNotFoundException 不再 CultureInfo 无效 | 更新日期: 2023-09-27 18:32:25
使用 es-CA
创建区域性信息,这显然是不正确的,应该会引发异常,但不再如此。
这之前抛出了一个CultureNotFoundException
:new CultureInfo("es-CA")
。它现在似乎回退到es
"未知区域设置"。虽然,做像xy-ZZ
这样的事情也有效,这很奇怪?
为什么这不再引发异常?这在最新版本的 .NET 中是否发生了更改?
更新 1
该文档提到了以下内容:
如果操作系统不支持该区域性,并且名称不是补充区域性或替换区域性的名称,则该方法将引发 CultureNotFoundException 异常。
在 Windows 7 上对此进行测试,它会抛出CultureNotFoundException
但在 Windows 10 上不会抛出异常。
注释添加答案。
由于 Windows 设计中的更改,如果名称与 BCP-47 匹配,现在不再有"无效区域性",因此 .NET Framework/.NET Core 不会引发异常,而是接受新的区域性。
您可以参考 GitHub 讨论,以及下面的引用,
由于框架依赖于操作系统来获取区域性,因此操作系统的 正在移动到模型,任何 BCP-47 区域性名称都变得有效,即使 操作系统不支持它。例如,Windows 10支持任何 格式良好的区域名称,即使操作系统也没有此类的真实数据 文化。例如,如果尝试在 视窗 10 它会成功。考虑到这一点,没有意义 具有区域性枚举,因为我们返回的任何集合并不意味着这些是 唯一支持的区域性。查看您的问题,您的解决方法是 可以接受。如果真的想有更好的方法,我们可以考虑 类似于CultureInfo.TryGetCulture(),但正如我之前所说 向前发展,几乎任何文化都是有效的。
我发布这个作为对OP问题帖子中几乎提出的两个问题的答案:
<小时 />在 Windows 10 的重大更改以支持
BCP-47
之后......
- 如何判断给定的
CultureInfo
对象是"真正的"文化,还是在代码中从头开始创建的虚假/人为/私有CultureInfo
?- 如何判断用户提供的
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 或更早版本上一样,只需检查:
CultureInfo.CultureTypes
没有设置CultureTypes.UserCustomCulture
标志。- 如果确实有
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
= 没有区域的语言名称,例如en
、fr
等 -
Specific
= 特定地区的语言名称,例如en-US
、en-GB
、fr-CA
、fr-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 CultureInfo
与 CultureInfo.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 文化 |框架文化 |