如何从异步上下文切换 MainThread 的 CurrentCulture?
How to switch CurrentCulture of MainThread from async context?
我有一个旧的 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 及更高版本上,您可以在 App.config
中将 NoAsyncCurrentCulture
开关设置为 true
以恢复旧行为:
<?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
我有一个旧的 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 及更高版本上,您可以在 App.config
中将 NoAsyncCurrentCulture
开关设置为 true
以恢复旧行为:
<?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