C# BackgroundWorker 的文化
Posted
技术标签:
【中文标题】C# BackgroundWorker 的文化【英文标题】:C# BackgroundWorker's culture 【发布时间】:2010-03-05 10:18:50 【问题描述】:我想为我的整个应用程序设置文化。我尝试了以下方法:
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(wantedCulture);
Application.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture);
它适用于当前线程,但后来我创建并启动了一个后台工作线程。当我创建工作线程时,当前线程使用 WantedCulture 执行,但工作线程将使用我计算机的文化运行。
有什么想法可以为整个应用程序设置文化吗?
【问题讨论】:
【参考方案1】:注意:过时的材料,请务必阅读底部的更新以了解 .NET 4.6 中的更改
是的,这是一个常见的请求,但它不可用。 Windows 总是将操作系统线程初始化为系统默认的 LCID,在控制面板的区域和语言选项小程序中配置。只要您自己创建线程,您就可以覆盖它。但这对于线程池线程和可能由运行您的进程的某种非托管代码(如 COM 服务器)创建的线程是不切实际的。
后一种情况是问题所在。 .NET 在由非托管代码创建的线程上运行托管代码没有任何问题。但它不能对线程的初始化方式做任何事情。这对于 CurrentUICulture 是正确的,但对于像 Thread.SetApartmentState() 这样的更晦涩的东西也是如此。不要低估这样一个线程在你的程序中运行代码的可能性,微软编写的 COM 服务器非常适合线程。
您将不得不用细齿梳理您的代码,并找到可能在您未创建的线程上运行的任何代码。任何事件处理程序都是可疑的,任何具有回调的 BeginXxx() 方法也是如此。 BackgroundWorker 肯定是较小的问题。
不覆盖线程的文化会产生非常微妙且难以诊断的错误。一个很好的例子是一个以字符串为键的 SortedList。当使用错误的区域性运行时,它会随机无法找到列表中实际存在的元素。由于列表不再在具有不同排序规则的另一种文化中排序。
如果我成功地吓到了你,那么我的信息就会传达出去。这发生在我身上,调试一个在丹麦机器上运行异常的非常大的程序的问题。我们没有丹麦语本地化,并强制 UI 以英语运行。工作线程使用以字符串为键的红黑树。当被要求与 Åårdvårks 打交道时,它随机失败了。花了我一个星期。
更新:此问题已在 .NET 4.5 中得到解决。 CultureInfo 类现在有一个DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture。设置后,它将用于初始化任何托管线程的文化而不是默认的 Windows 系统文化。我还不清楚它是如何与由本机代码启动并输入托管代码的线程进行交互的。
更新:这个问题在 .NET 4.6 中有更彻底的解决方案。文化现在自动流动,理想的行为。 CultureInfo.CurrentCulture() 的 MSDN 文章谈到了它。提供的信息仍然令人困惑,实验上它似乎也流向一个 Thread 对象,而不仅仅是一个任务或线程池线程,并且没有使用 DefaultThreadCurrentCulture。前进两步,后退一步,建议测试。
【讨论】:
【参考方案2】:我的解决方案是拥有一个中心区域性属性(Application.CurrentCulture 是每个线程),并在工作线程的开头将当前线程区域性设置为此。作业系统对此有所帮助,因为您可以轻松地在工作项之前和之后执行通用代码,并且作业系统类可以保持其作业可访问的文化,因此您不需要全局变量。
【讨论】:
【参考方案3】:简单地说; 不要这样做。
不要在除主线程 (Thread.CurrentThread
) 之外的任何其他线程上执行任何文化特定格式。在其他线程上获得正确的文化——创建的每个其他线程——只是一种痛苦,迟早你会忘记正确设置它。最好一起避免痛苦,只在保证您处于正确文化设置的线程上进行文化特定的格式化、转换等。
【讨论】:
【参考方案4】:您不能对每个新创建的线程都执行此操作。您应该手动完成(但我认为为线程池线程设置区域性不是一个好主意!)。也许您的应用程序应该依赖于 Application.CurrentCulture 或其他一些全球性的东西..
【讨论】:
【参考方案5】:Windows 总是将操作系统线程初始化为系统默认的 LCID, 在 Control 中的区域和语言选项小程序中配置 面板。
不幸的是,我不同意这一点,并找到了相反的观点。
系统安装为美国英语。 转到控制面板将所有内容更改为丹麦语并复制到所有帐户。 重新启动。
运行控制台应用程序,它以丹麦语运行。 运行网络应用程序询问浏览器它说丹麦语。 从网络应用程序启动线程,它是以美国而不是丹麦语启动的,我不知道为什么。
【讨论】:
【参考方案6】:我知道这个话题很老,但我发现自己陷入了“操作系统文化的话题”问题。
我解决了这个问题:由于 BackgroundWorker 在 UserControl 中(如果它在 Form 中则有效,依此类推...)我在构造 UserControl(或 Form)时在 UserControl(或 Form)中设置了一个字段。在 DoWork 事件处理程序中,我在操作中使用此字段。代码如下:
/// <summary>
/// Culture in which the GUI creates the control.
/// </summary>
private readonly CultureInfo _currentCulture;
/// <summary>
/// Default constructor.
/// </summary>
public MyControl()
InitializeComponent();
_currentCulture = CultureInfo.CurrentUICulture;
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
ExampleClass.DoCultureDependentOperation(_currentCulture);
【讨论】:
以上是关于C# BackgroundWorker 的文化的主要内容,如果未能解决你的问题,请参考以下文章
C# form发起backgroundworker 当form close时 backgroundworker 还会继续工作吗