6

Невозможно установить все приложение .net в другую культуру, отличную от культуры профиля пользователя в .net. Соответствующий способ управления cultureinfo, по-видимому, использует специальные методы для таких объектов, как DateTime.Threading, CultureInfo .net, TPL, PLINQ

Однако, имея дело с огромным количеством устаревшего кода (не весь код под вашим контролем), этого достичь невозможно. Для этого можно, например, создать подкласс/оболочку для Thread och Threadpool и установить требуемую культуруinfo перед выполнением делегата, или же сам делегат может содержать набор культуры. (трудно проверить и подвергнуть ошибкам ...)

Глядя на TPL, более конкретно PLINQ, однако мне трудно, если не невозможно, изменить настройки культуры централизованным образом.

Любые предложения, которые касаются overovering thread/application-cultureinfo в устаревшем коде?

Спасибо!

ответ

6

Когда поток запускается, его культура изначально определяется с использованием GetUserDefaultLCID из Windows API. Я не нашел пути (я предполагаю, что нет способа) переопределить это поведение. Единственное, что вы можете сделать, - это установить культуру потока потом.

Я написал расширение. Для этого:

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() вам может потребоваться вызвать SetCulture() после каждого AsParallel(). Я не уверен, что есть одно место для добавления .SetCulture() (или одно место для AsParallel, если на то пошло), поэтому я просто добавил .SetCulture() после каждого вызова AsParallel(), и это отлично поработало.

Кроме того, вы можете рассмотреть возможность установки 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 
2

Начиная с .NET 4.5 вы сможете определить культуру для всего AppDomain (см пункт под названием «Core New Особенности и улучшения »).

0

Когда я создаю задачу с помощью TPL, я передаю Культуру из текущего потока пользовательского интерфейса в фоновый поток, используя объект состояния.

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