如何从异步上下文切换MainThread的CurrentCulture?

问题描述

我有一个旧的API,它会以这种方式切换当前的区域性:

private void ChangeCulture(int lcid)
    {
        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ChangeCulture Culture Start: {Thread.CurrentThread.CurrentCulture}");

        var newCulture = CultureInfo.GetCultureInfo(lcid);

        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] Changing culture of currentThread to: {newCulture}");

        Thread.CurrentThread.CurrentCulture = newCulture;
        Thread.CurrentThread.CurrentUICulture = newCulture;

        // Old framework compatibility (not important for this example)
        CultureInfo.DefaultThreadCurrentCulture = newCulture;
        CultureInfo.DefaultThreadCurrentUICulture = newCulture;

        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}] ChangeCulture Culture End: {Thread.CurrentThread.CurrentCulture}");
    }

以前,代码是从同步上下文中调用的。但是,由于现在需要从异步上下文中调用代码。就像这里:

private async void Button_Click(object sender,RoutedEventArgs e)
    {
        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}]Culture Start: {Thread.CurrentThread.CurrentCulture}");
        if (this.currrentLcid == 1031)
        {
            await Task.Delay(1000);
            this.ChangeCulture(1033);
            this.currrentLcid = 1033;
        }
        else
        {
            await Task.Delay(1000);
            this.ChangeCulture(1031);
            this.currrentLcid = 1031;
        }

        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}]Culture End: {Thread.CurrentThread.CurrentCulture}");
    }

输出:

[1]Culture Start: de-DE
[1] ChangeCulture Culture Start: de-DE
[1] Changing culture of currentThread to: en-US
[1] ChangeCulture Culture End: en-US
[1]Culture End: en-US

具有异步执行的文化流。但是它不会在全球范围内回流。如果我打电话:

    private void CheckCulture_Click(object sender,RoutedEventArgs e)
    {
        Debug.WriteLine($"[{Thread.CurrentThread.ManagedThreadId}]CheckCulture_Click: {Thread.CurrentThread.CurrentCulture}");
    }

输出:

[1]CheckCulture_Click: de-DE

一切都是MainThread。 (ManagedThreadId = 1)

.NET Framework 4.8

如何在不了解调用上下文的情况下在全球范围内切换当前的文化?

解决方法

在.NET Core中,这些属性实现为AsyncLocal<T>,简而言之,意味着对它们的任何更新只会影响当前的异步控制流,例如async方法。

根据要完成的任务,您可以考虑创建并设置自己的静态CultureInfo属性。

在.NET Framework 4.6和更高版本上,您可以在NoAsyncCurrentCulture中将true开关设置为App.config,以恢复旧的行为:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <startup> 
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
  </startup>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Globalization.NoAsyncCurrentCulture=true"/>
  </runtime>
</configuration>

<AppContextSwitchOverrides> element

Retargeting Changes for Migration from .NET Framework 4.5 to 4.6

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...