Threading, CultureInfo.net, TPL, PLINQ

It is not possible to install the entire .net application in a different culture than the user profile culture in .net. The appropriate way to control cultureinfo seems to use special methods for objects such as DateTime.

However, dealing with a huge amount of legacy code (not all the code under your control), this is impossible to achieve. To do this, for example, you can create a subclass / wrapper for Thread och Threadpool and set the required info culture before executing the delegate, or the delegate itself can contain a culture set. (hard to check and error ...)

Looking at TPL, or rather PLINQ, it’s hard for me, if not impossible, to change culture settings in a centralized way.

Any suggestions regarding overovering thread / application-cultureinfo in legacy code?

Thanks!

+6
multithreading plinq task-parallel-library cultureinfo
source share
4 answers

When a thread starts, its culture is initially defined using GetUserDefaultLCID from the Windows API. I have not found a way (I assume there is no way) to override this behavior. The only thing you can do is set up a flow culture later.

I wrote an extension. For this:

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

So, if you use it immediately after splitting the original source using .AsParallel (), you will get what you want.

  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(); 
+6
source share

Starting with .NET 4.5, you can define a culture for the entire AppDomain (see the section entitled β€œKey New Features and Improvements,”).

+2
source share

Surprisingly, this extension did not slow down my PLINQ queries - which I could measure.

In a complex query with many AsParallel () calls, you may need to call SetCulture () after each AsParallel (). I'm not sure if there is one place to add .SetCulture () (or one place for AsParallel, for that matter), so I just added .SetCulture () after each AsParallel () call, and it worked fine.

In addition, you may also consider installing CurrentUICulture. for example, using PLINQ to search for a collection of business objects to search for business objects with broken rules (CSLA structure, Broken Rules assembly) will cause PLINQ streams (stream stream flows) to look for localized (our requirements) string resources to set the string errors (RuleArgs. Description).

I just need to expand the ParallelQueryCultureExtensions extension. This worked for me (I have to use VB.NET, therefore ...):

 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 
+1
source share

When I create a task using TPL, I pass the culture from the current user interface to the background thread using a state object.

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

All Articles