7

当前文化信息(CurrentCulture 和/或 CurrentUICulture)是正在运行的线程的属性,这让我觉得这是一个奇怪的设计选择。至少,在流程级别上,此类事情的范围似乎应该是上一级的。

但是,一旦您听到基本原理,这些事情通常就会变得有意义。找出为什么 .NET 设计者认为 Thread 是放置此属性的正确位置可能会很有启发性。

4

4 回答 4

10

首先,这并不是他们的选择。这个决定是在他们开始之前很久就做出的,文化是操作系统线程的属性。例如,查看 Get/SetThreadLocale() API 函数的 SDK 文档。

这并不能完全解释这一点,他们已经虚拟化了其他操作系统功能,尽管这个很难虚拟化,因为很多 API 都是文化敏感的,尤其是 COM 的。

下一个很好的理由是因为在整个过程范围内改变文化非常难以实施。这是一个无法解决的竞争条件。其他一些线程很可能正在格式化具有文化亲和力的数据。虽然锁可以防止它在更改时使用区域性属性,但它不能阻止它在格式化调用链的中间更改。这将要求他们采取某种全局锁并在格式化作业期间保持它。死锁的可能性很大

这还有另一个方面,我认为这是真正的问题。它与 Thread.ExecutionContext 属性有关。框架使用它来将线程状态从一个线程“流动”到另一个线程。将诸如安全上下文之类的东西灌输到工作线程上非常晦涩但很重要。如果该上下文也可以灌输文化,那将是理想的,这样您就可以确保您启动的任何工作人员都具有您选择的相同文化而不是操作系统默认值。

没有,我真的不知道为什么。可能是因为我给出的第一个原因。然而,这确实使得改变线程的文化非常危险。可能导致的错误类型非常微妙。就像在具有非操作系统默认区域性的主线程中创建一个以字符串为键的 SortedDictionary。然后发现工作线程偶尔不能再找到东西了,因为字符串排序规则不同。


编辑:.NET 4.5 中的这个问题有所缓解,它支持新的静态 CultureInfo.DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 属性。


EDIT2:文化现在如 .NET 4.6 第 4 段所述流动。这应该可以缓解所有担忧。

于 2010-11-14T11:46:34.570 回答
6

我会试一试-也许是因为您需要使用不同文化的多个同时线程?如果您想到一个多语言的 asp.net 网站,您不希望该过程被绑定到一种语言......一个网络请求可能是 EN-US 和另一个 fr-FR。

于 2010-11-14T03:37:18.780 回答
2

窗口句柄本身是线程特定的。您永远不应该在不同线程的上下文中使用窗口句柄(用于顶级窗口、子控件等),因为实现窗口处理 (GDI) 的代码本身不是线程安全的。由于 UICulture 是特定于窗口的,这意味着它也被定义在线程级别。

其他 GUI 方面也是线程特定的,例如活动窗口和焦点。虽然有一个 API,但我不记得名字了,它将来自不同线程的 UI 上下文连接在一起,以便在多个用户界面线程之间共享焦点、活动窗口。

于 2010-11-14T03:36:49.843 回答
2

CurrentCulture 只不过是对 CultureInfo 的引用,因此允许它挂在线程上不会丢失太多(只是一个引用的内存)。同时,您可以获得允许用户精细控制每个线程的当前文化的可能性——这在某些类型的应用程序中非常重要。

对于现代软件的非英语用户来说,拥有这种细粒度的一个原因可能更明显。我必须定期在 Windows 中切换键盘,并且可以使用一个全局键盘快捷键轻松完成此操作。将 CultureInfo 放在线程上使我们能够轻松地在 .NET 应用程序中实现类似的逻辑,而无需更改每个进程的信息。

想到的用法示例:

  1. 我可能想要一个快捷方式,可以根据当前用户的请求在短时间内更改我的程序中的文化(许多应用程序需要允许多个用户在同一工作站和同一会话中)。但是相同的过程可能必须继续使用机器上的默认 CultureInfo 以例如始终使用相同的时间戳格式进行日志记录。

  2. 您可能还有一个报告解决方案,可以为一家全球公司的多个分支机构提供报告,每个分支机构都有自己的文化。如果您可以更改每个线程的 CultureInfo,您的设计将受到更少的限制。

  3. 另一个原因是,如果您想使用特定的文化写入文件,但您不想在写入函数中指定文化(例如,因为这些函数已经被写入)。然后,您可以轻松更改该逻辑,而无需在其他线程上更改它,这些线程可能正在做需要默认文化的工作。

于 2010-11-14T04:22:12.177 回答