为什么CurrentCulture是Thread的属性?

7

我认为,当前区域信息(CurrentCulture和/或CurrentUICulture)是运行线程的属性,这似乎是一种奇怪的设计选择。至少,在这种情况下,这样的东西的范围应该在进程级别上。

但是,当你了解到.NET设计师为什么决定将此属性放在Thread上时,这些事情通常都有意义。这可能会让人们恍然大悟。

4个回答

10
首先,这不是他们真正的选择。这个决定在他们开始之前就已经做出了,因为文化是操作系统线程的属性。例如,查看SDK文档中的Get/SetThreadLocale() API函数。
这并不能完全解释它,他们还虚拟化了其他操作系统功能,尽管这个很难虚拟化,因为许多API都与文化有关,特别是COM API。
下一个好的原因是,进程范围内更改文化非常难以实现,这是一个无法解决的竞争条件。一些其他的线程可能会在格式化具有文化相关性的数据时处于中间状态。虽然锁定可以防止它在更改时使用文化属性,但它无法防止它在一系列格式化调用中间进行更改。这将需要他们采取某种全局锁,并在格式化作业的持续时间内保持该锁定。死锁是非常可能的。
还有另一个方面,我认为这是真正的问题。它与Thread.ExecutionContext属性有关。框架使用它来将线程状态从一个线程传递到另一个线程。非常模糊但对于将安全上下文注入工作线程等事情非常重要。如果该上下文也可以注入文化,则将非常理想,这样您就可以确保任何您启动的工作程序都具有与您选择的文化相同的文化,而不是操作系统默认值。
它没有,我真的不知道为什么。可能是因为我给出的第一个原因。然而,这确实使更改线程的文化非常危险。可能会引起非常微妙的错误,例如在主线程中使用字符串作为键创建SortedDictionary,并使用非操作系统默认文化。然后发现一个工作线程偶尔无法再找回东西,因为字符串排序规则是不同的。
编辑:在.NET 4.5中,这个问题有所缓解,它支持新的静态CultureInfo.DefaultThreadCurrentCulture和DefaultThreadCurrentUICulture属性。

编辑2: 目前在.NET 4.6中,文化流程如第4段所描述。这应该消除所有的顾虑。


6

我来试一试 - 或许是因为需要使用不同文化的多个并发线程?如果你想要一个多语言的ASP.NET网站,你不希望进程被绑定在一个语言上...一个Web请求可能是EN-US,另一个可能是fr-FR。


2

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

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


2
当前文化是对CultureInfo的引用,因此允许其挂在线程上不会有太大损失(仅一个引用的内存)。同时,您可以使用户对每个线程的当前区域设置进行精细控制,这在某些类型的应用程序中非常重要。
将它细分可能更明显的原因是现代软件的非英语用户。例如我经常需要在Windows中切换键盘,并能够轻松地使用一个全局键盘快捷方式完成此操作。在线程上具有CultureInfo使我们能够轻松地在.NET应用程序中实现类似的逻辑,而无需针对每个进程更改该信息。
以下是一些使用示例:
1. 我可能想要一个快捷方式,在请求当前用户时为我的程序短时间更改区域设置(许多应用程序需要允许同一工作站和同一会话中的多个用户)。但是,同一进程可能必须继续使用机器上的默认CultureInfo,例如始终使用相同的时间戳格式记录日志。
2. 您还可以拥有一个报告解决方案,可为全球公司的几个分支机构转储报告,每个分支机构都有自己的CultureInfo。如果您可以更改每个线程的CultureInfo,则设计将不受限制。
3. 另一个原因是,如果您想使用特定的CultureInfo编写文件,但不想在写函数中指定CultureInfo(例如,因为这些函数已经编写好了)。然后,您可以轻松地更改该逻辑,而无需在可能需要默认Culture的其他线程上进行更改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接