无法将整个.net应用程序设置为除.net中的用户配置文件之外的其他文化。控制cultureinfo的适当方法似乎是在DateTime等对象上使用专用方法。
但是,当处理大量遗留代码(并非所有代码都在您的控制之下)时,这是不可能实现的。因此,可以例如创建Thread och Threadpool的子类/包装器,并在执行委托之前设置所需的cultureinfo,或者可以要求委托本身包含一组文化。 (难以验证并容易出现错误......)
关注TPL,更具体地说是PLINQ,但我发现以集中的方式改变文化背景很难(如果不是不可能的话)。
在遗留代码中处理overriding thread / application-cultureinfo的任何建议?
谢谢!
答案 0 :(得分:6)
启动线程时,最初使用Windows API中的GetUserDefaultLCID确定其文化。我发现没有办法(我认为没有办法)来覆盖这种行为。你唯一能做的就是之后设置线程文化。
我写了一个扩展名。为此:
public static class ParallelQueryCultureExtensions
{
public static ParallelQuery<TSource> SetCulture<TSource>(this ParallelQuery<TSource> source, CultureInfo cultureInfo)
{
SetCulture(cultureInfo);
return source
.Select(
item =>
{
SetCulture(cultureInfo);
return item;
});
}
private static void SetCulture(CultureInfo cultureInfo) {
if (Thread.CurrentThread.CurrentCulture != cultureInfo) {
Thread.CurrentThread.CurrentCulture = cultureInfo;
}
}
}
因此,如果您在使用.AsParallel()分割原始源后立即使用它,您将得到您想要的。
CultureInfo kaCulture = CultureInfo.GetCultureInfo("ka-Ge");
int[] array = new int[100];
Random random = new Random();
int index =0;
Array.ForEach(array, i => { array[index++] = index;});
array
.AsParallel()
.SetCulture(kaCulture)
.ForAll(
i =>
{
Thread.Sleep(random.Next(5));
Console.WriteLine("Thread-{0} \t Culture-'{1}' \t Element-{2}", Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.CurrentCulture, i);
});
Console.WriteLine("Press any key to quit");
Console.ReadKey();
答案 1 :(得分:2)
从.NET 4.5开始,您将能够为整个AppDomain定义文化(请参阅标题为“核心新功能和改进”的段落)。
答案 2 :(得分:1)
令人惊讶的是,这个扩展并没有减慢我的PLINQ查询 - 我可以衡量。
在具有许多AsParallel()调用的复杂查询中,您可能必须在每个AsParallel()之后调用SetCulture()。 我不确定是否有一个地方要添加.SetCulture()(或者AsParallel的一个地方),所以我在每次AsParallel()调用之后添加了.SetCulture(),这非常有用。
此外,您也可以考虑设置CurrentUICulture。 例如使用PLINQ搜索业务对象集合以查找具有损坏规则的Business Objects(CSLA框架,Broken Rules集合)将导致PLINQ线程(线程池线程)查找本地化(我们的要求)字符串资源以设置错误字符串(RuleArgs。描述)。
我只需要扩展ParallelQueryCultureExtensions扩展。 这对我很有用(我必须使用VB.NET,因此......):
Public Module PLINQExtensions
<Extension()> _
Public Function SetCulture(Of TSource)(ByVal source As ParallelQuery(Of TSource), ByVal culture As CultureInfo, ByVal uiCulture As CultureInfo) As ParallelQuery(Of TSource)
SetCulture(culture, uiCulture)
Return source.Select(Function(item)
SetCulture(culture, uiCulture)
Return item
End Function
)
End Function
<Extension()> _
Private Sub SetCulture(ByVal culture As CultureInfo, ByVal uiCulture As CultureInfo)
If (Not Thread.CurrentThread.CurrentCulture.Equals(culture)) Then
Thread.CurrentThread.CurrentCulture = culture
End If
If (Not Thread.CurrentThread.CurrentUICulture.Equals(uiCulture)) Then
Thread.CurrentThread.CurrentUICulture = uiCulture
End If
End Sub
End Module
答案 3 :(得分:0)
当我使用TPL创建任务时,我使用状态对象将Culture从当前UI-Thread传递给后台线程。
private void WorkProcessingAsync(IWorkItem workItem)
{
IsBusy = true;
/* =============================
* Create a TPL Task and pass the current UiCulture in an state Object to resolve the correct .resx file for translation / globalisation / Multila`enter code here`nguate features in Background Thread
* ==============================*/
Task<IWorkItem> task = Task.Factory.StartNew((stateObj) =>
{
// here we are already in the task background thread
// save cast the given stateObj
var tuple = stateObj as Tuple<IWorkItem, CultureInfo>;
Debug.Assert(tuple != null, "tuple != null");
Thread.CurrentThread.CurrentUICulture = tuple.Item2; // Here we set the UI-Thread Culture to the Background Thread
var longRunningOperationAnswer = LongRunningOperation.DoLongWork(tuple.Item1);
return longRunningOperationAnswer;
}, new Tuple<IWorkItem, CultureInfo>(workItem, Thread.CurrentThread.CurrentUICulture)); // here we pass the UI-Thread Culture to the State Object
/* =======================================================================
* Handle OnlyOnRanToCompletion Task and process longRunningOperationAnswer back in UiThread
* =======================================================================*/
task.ContinueWith((t) =>
{
IsBusy = false;
// handle longRunningOperationAnswer here in t.Result
Log.Debug("Operation completet with {0}", t.Result);
}, CancellationToken.None
, TaskContinuationOptions.OnlyOnRanToCompletion
, TaskScheduler.FromCurrentSynchronizationContext());
/* =======================================================================
* Handle OnlyOnFaulted Task back in UiThread
* =======================================================================*/
task.ContinueWith((t) =>
{
IsBusy = false;
AggregateException aggEx = t.Exception;
if (aggEx != null)
{
aggEx.Flatten();
Log.ErrorFormat("The Task exited with Exception(s) \n{0}", aggEx);
foreach (Exception ex in aggEx.InnerExceptions)
{
if (ex is SpecialExaption)
{
//Handle Ex here
return;
}
if (ex is CustomExeption)
{
//Handle Ex here
return;
}
}
}
}, CancellationToken.None
, TaskContinuationOptions.OnlyOnFaulted
, TaskScheduler.FromCurrentSynchronizationContext());
}