.net - example - task parallel library c#
En.Net: ¿la mejor manera de mantener CurrentCulture en un nuevo hilo? (4)
En un proyecto .Net 4.0 WPF , necesitamos mantener la misma CurrentCulture en cada hilo que tenemos en el hilo principal.
Dado, podemos inicializar la cultura de un nuevo hilo con un código como el siguiente:
Mantener la información en una variable (contexto)
context.CurrentCulture = Thread.CurrentThread.CurrentCulture; context.CurrentUICulture = Thread.CurrentThread.CurrentUICulture;
En el nuevo hilo, inicialice desde el contexto guardado
Thread.CurrentThread.CurrentCulture = context.CurrentCulture; Thread.CurrentThread.CurrentUICulture = context.CurrentUICulture;
Pero en esta era de TPL, la programación asíncrona y los delegados lambda, no se siente bien.
Y sí, podemos cambiar la cultura mientras se ejecuta la aplicación, pero esa es otra historia.
¿Conoce alguna configuración, propiedad o configuración que debamos inicializar para realizar un seguimiento?
Cuando creo Tareas con el TPL, siempre paso la Cultura desde el UI-Thread actual. Ver código de muestra a continuación.
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 / Multilanguate 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());
}
Necesitaba pasar la cultura para resolver la traducción correcta. Resx para la traducción
No entiendo por qué el Sr. Passant advierte sobre esto y, al mismo tiempo, dice que está bien hacer cambios "temporales" en la cultura de "subprocesos locales". Ninguna cultura de subprocesos es realmente un subproceso local: está disponible para cualquier cosa que pueda hacer referencia al subproceso a través de propiedades públicas, como hemos visto. Y si está bien cambiarlo por un tiempo corto, ¿por qué no está bien cambiarlo por un tiempo más largo? ¿Dónde cruzas la línea y por qué?
Tampoco entiendo realmente la sensación del OP de que "no debería ser necesario" escribir un código para copiar lo que él quiere copiar. Es posible que desee colocar este código en algún lugar donde pueda reutilizarlo, pero aparte de eso, realmente no veo el problema con el código. En mi libro, es bastante más directo y maravilloso que cualquier expresión lambda que haya visto, y haría el trabajo bastante bien. Escribir código de fantasía por el hecho de que sea elegante no es mi estilo, al menos.
Podrías hacer algo como esto:
// Program.cs
static CultureInfo culture, uiCulture;
[STAThread]
static public void Main()
{
var t = Thread.CurrentThread;
culture = t.CurrentCulture;
uiCulture = t.CurrentUICulture;
}
static public Thread CreateThread()
{
return new Thread() { CurrentCulture = culture, CurrentUICulture = uiCulture }; }
}
No hay una buena manera, evitar esto a toda costa. El problema fundamental es que la cultura no es parte de Thread.ExecutionContext, no fluye de un hilo a otro. Este es un problema sin solución, la cultura es una propiedad de un hilo nativo de Windows. Siempre se inicializará en la cultura del sistema como se seleccionó en el applet de Región e Idioma del Panel de Control.
Hacer cambios temporales de subprocesos a la cultura está bien, tratar de cambiar "el proceso" a otra cultura es una fuente de errores que estará buscando durante meses. El orden de intercalación de cadenas es la fuente de problemas más desagradable.
EDIT: este problema se solucionó en .NET 4.5 con las propiedades CultureInfo.DefaultThreadCurrentCulture y DefaultThreadCurrentUICulture.
EDIT: y obtuve la solución real en .NET 4.6, la cultura ahora fluye de un hilo a otro. Consulte el artículo de MSDN para CultureInfo.CurrentCulture para obtener detalles. Tenga en cuenta que la descripción no coincide exactamente con el comportamiento, se requieren pruebas.
Por cierto, me doy cuenta de que, si bien la cultura predeterminada proviene de la "Configuración regional" de Windows, probablemente se puede anular en la configuración de .NET.
Si se tratara de una aplicación ASP.NET, usaría el elemento de globalization
en web.config
. Probablemente comenzaría en algún lugar como aquí para aprender sobre la localización en WPF:
http://msdn.microsoft.com/en-us/library/ms788718.aspx#workflow_to_localize
(¿Soy yo o Microsoft usa las palabras globalización y localización, de manera confusa, indistintamente?)