6

不可能將整個.net應用程序設置爲除.net中的用戶配置文件以外的其他文化。控制cultureinfo的適當方式似乎是在諸如DateTime之類的對象上使用專用方法。但是,當處理大量遺留代碼(並非所有代碼都在您的控制下)時,這是不可能實現的。因此,人們可以創建一個子類/包裝到線程或線程池,並在委託執行之前設置所需的文化信息,或者可以要求委託本身包含一組文化。 (很難驗證和容易misstakes ...)Threading,CultureInfo .net,TPL,PLINQ

看着TPL,更具體PLINQ,但我覺得很難,如果不是不可能的,在一個集中的方式更改區域性設置。

任何建議,處理在舊代碼中覆蓋thread/application-cultureinfo?

謝謝!

回答

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

這工作完美,至少直到我可以移動到.net 4.5 :) – Porco 2012-06-11 22:40:22

1

令人驚訝的是,這個擴展沒有減慢我的PLINQ查詢 - 我可以測量。

在一個具有許多AsParallel()調用的複雜查詢中,您可能必須在每個AsParallel()後調用SetCulture()。 我不確定是否有一個點需要添加.SetCulture()(或者AsParallel的一個點),所以我在每次AsParallel()調用之後添加了.SetCulture(),並且效果很好。

此外,您也可以考慮設置CurrentUICulture。 例如使用PLINQ搜索Business Object集合以查找具有破壞規則的業務對象(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 
2

.NET 4.5開始,你就可以定義培養一個完整的應用程序域(見第標題爲「新核心功能和改進「)。

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()); 
    }