代码之家  ›  专栏  ›  技术社区  ›  Toto

C后台员工文化

  •  19
  • Toto  · 技术社区  · 14 年前

    我想为我的整个应用程序设置文化。我尝试了以下方法:

    Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture);
    Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(wantedCulture);
    Application.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture);
    

    它适用于当前线程,但稍后我将创建并启动一个后台工作线程。创建工作线程时,当前线程将使用所需的区域性执行,但工作线程将使用计算机的区域性运行。

    对整个应用程序的文化设置有什么想法吗?

    6 回复  |  直到 8 年前
        1
  •  35
  •   Hans Passant    8 年前

    注:注明日期的材料,请务必阅读底部的更新以了解.NET 4.6中的更改

    是的,这是一个常见的请求,但不可用。Windows总是将操作系统线程初始化为系统默认LCID,配置在“控制面板”的“区域和语言选项”小程序中。只要您自己创建线程,就可以覆盖它。但对于线程池线程和可能是由运行进程的某种非托管代码(如COM服务器)创建的线程,这是不实际的。

    后一种情况就是问题所在。.NET在由非托管代码创建的线程上运行托管代码没有问题。但是它不能改变线程初始化的方式。对于currentuiculture也是如此,但对于thread.setApartmentState()这样更模糊的东西也是如此。不要低估这样一个线程在程序中运行代码的可能性,微软编写的com服务器非常喜欢线程。

    你必须用一把细齿梳子仔细检查你的代码,找出任何可能在你没有创建的线程上运行的代码。任何事件处理程序都是可疑的,任何具有回调的beginxxx()方法都是可疑的。后台工作绝对是次要的问题。

    不重写线程的区域性会产生 非常 很微妙,很难诊断。一个很好的例子是一个sortedlist,它可以在一个字符串上进行键控。当使用错误的区域性运行时,它将随机找不到列表中实际存在的元素。导致列表在另一个具有不同排序规则的区域性中不再排序。

    如果我够吓唬你的话,我就会把我的信息传达出去。这件事发生在我身上,调试一个在丹麦机器上运行不当的大型程序的问题。我们没有丹麦语的本地化,并强迫用户界面用英语运行。一个工作线程使用了一个红黑树,它有一个字符串作为密钥。当被要求处理RDVRK时,它随机失败。我花了一个星期。


    更新:此问题已在.NET 4.5中解决。Cultureinfo类现在有一个 DefaultThreadCurrentCulture 和DefaultThreadCurrentuiCulture。设置后,它将用于初始化任何托管线程的区域性,而不是默认的Windows系统区域性。它究竟是如何与由本机代码启动并输入托管代码的线程交互的,我还不清楚。


    更新:这个问题在.net 4.6中有一个更彻底的解决方案。文化现在自动流动,这是理想的行为。的MSDN文章 CultureInfo.CurrentCulture() 谈谈这个。提供的信息至今仍令人困惑,实验上它似乎也流向了线程对象,而不仅仅是任务或线程池线程,并且未使用DefaultThreadCurrentCulture。向前两步,向后一步,建议进行测试。

        2
  •  1
  •   OregonGhost    14 年前

    我的解决方案是拥有一个中心区域性属性(application.current culture是每个线程的),并在工作线程的开头将当前线程区域性设置为该属性。作业系统有助于实现这一点,因为您可以轻松地在工作项之前和之后执行泛型代码,并且作业系统类可以保存其作业可访问的区域性,因此不需要全局变量。

        3
  •  1
  •   Kjetil Klaussen    12 年前

    简单地说; 不要这样做

    不要在主线程以外的任何其他线程上执行任何区域性特定的格式设置( Thread.CurrentThread )在其他线程(每创建一个其他线程)上获得正确的区域性只是一种痛苦,迟早你会忘记正确设置它。最好避免所有这些痛苦,并且只在线程上执行特定于区域性的格式化、转换等操作,这样就可以保证您处于正确的区域性设置中。

        4
  •  0
  •   Sergey Teplyakov    14 年前

    不能对每个新创建的线程都这样做。你应该手工操作(但我不认为为线程池线程设置区域性是个好主意!)。也许您的应用程序应该依赖于application.currentculture或其他一些全局性的东西。

        5
  •  0
  •   Chris Ward    11 年前

    Windows总是将操作系统线程初始化为系统默认LCID, 在控制中的“区域和语言选项”小程序中配置 面板。

    不幸的是,我不得不不同意这一点,并找到了相反的结果。

    系统安装为美式英语。 转到控制面板将所有内容更改为丹麦语并复制到所有帐户。 重新启动。

    运行丹麦语的控制台应用程序。 运行网络应用程序ask browser,上面写着danish。 从web应用程序启动thread,它是以我们不是丹麦人的身份启动的,我不明白为什么。

        6
  •  0
  •   Fleve    9 年前

    我知道这个话题已经过时了,但我发现自己陷入了一个“操作系统文化线程”的问题。

    我是这样解决的:由于backgroundworker在一个usercontrol中(如果它是一个表单,那么它是有效的……),所以我在构建时在usercontrol(或表单)中设置了一个字段。在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);
        }