6

.net アプリケーション全体を、.net のユーザー プロファイル カルチャ以外の別のカルチャに設定することはできません。cultureinfo を制御する適切な方法は、DateTime などのオブジェクトに対して専用のメソッドを使用することです。

ただし、膨大な量のレガシー コード (すべてのコードが管理下にあるわけではない) を扱う場合、これを実現することはできません。そのため、たとえば Thread および Threadpool のサブクラス/ラッパーを作成し、デリゲートが実行される前に必要な cultureinfo を設定するか、デリゲート自体に一連のカルチャを含めるように要求することができます。(検証が難しく、間違いが起こりやすい...)

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 に答える
1

驚くべきことに、この拡張機能によって PLINQ クエリの速度が低下することはありませんでした。これは測定できました。

多くの AsParallel() 呼び出しを含む複雑なクエリでは、各 AsParallel() の後に SetCulture() を呼び出す必要がある場合があります。.SetCulture() を追加する場所が 1 つ (または AsParallel の場合は 1 つ) あるかどうかわからないので、各 AsParallel() 呼び出しの後に .SetCulture() を追加したところ、うまくいきました。

さらに、CurrentUICulture の設定も検討できます。たとえば、PLINQ を使用してビジネス オブジェクト コレクションを検索し、壊れたルール (CSLA フレームワーク、壊れたルール コレクション) を持つビジネス オブジェクトを見つけると、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 に答える