6

除了 .net 中的用户配置文件区域性之外,无法将整个 .net 应用程序设置为另一种区域性。控制cultureinfo 的适当方法似乎是对对象使用专用方法,例如DateTime。

但是,在处理大量遗留代码(并非所有代码都在您的控制之下)时,这是不可能实现的。因此,例如可以为 Thread och Threadpool 创建一个子类/包装器,并在执行委托之前设置所需的文化信息,或者可能要求委托本身包含一组文化。(难以验证并且容易出错......)

看看 TPL,更具体地说是 PLINQ,我发现很难,如果不是不可能的话,以集中的方式改变文化设置。

在遗留代码中处理覆盖线程/应用程序文化信息的任何建议?

谢谢!

4

4 回答 4

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(); 
于 2011-08-04T21:37:40.947 回答
2

.NET 4.5开始,您将能够为整个 AppDomain 定义文化(请参阅标题为“核心新功能和改进”的段落)。

于 2011-09-24T10:18:28.080 回答
1

令人惊讶的是,这个扩展并没有减慢我的 PLINQ 查询速度——我可以测量。

在具有许多 AsParallel() 调用的复杂查询中,您可能必须在每个 AsParallel() 之后调用 SetCulture()。我不确定是否有一个位置可以添加 .SetCulture() (或者 AsParallel 的一个位置),所以我只是在每次 AsParallel() 调用之后添加了 .SetCulture() ,效果很好。

此外,您也可以考虑设置 CurrentUICulture。例如,使用 PLINQ 搜索业务对象集合以查找具有破坏规则的业务对象(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
于 2011-08-19T16:21:57.253 回答
0

当我使用 TPL 创建任务时,我使用状态对象将文化从当前 UI 线程传递到后台线程。

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());
    }
于 2012-01-27T09:24:16.650 回答