C # Background La cultura del lavoro

Mi piacerebbe impostare la cultura per tutta la mia applicazione. Ho provato il seguente:

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture); Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(wantedCulture); Application.CurrentCulture = CultureInfo.CreateSpecificCulture(wantedCulture); 

Funziona per il thread corrente, ma in seguito creerò e avvierò un thread di background worker. Quando creo il worker, il thread corrente viene eseguito con wantedCulture ma il thread worker verrà eseguito con la cultura del mio computer.

Qualche idea per impostare la cultura per l’intera applicazione?

NOTA: materiale datato, assicurarsi di leggere l’aggiornamento in fondo per le modifiche in .NET 4.6

Sì, questa è una richiesta comune ma non è disponibile. Windows inizializza sempre un thread del sistema operativo sull’LCID predefinito del sistema, configurato nell’applet Opzioni internazionali e della lingua nel Pannello di controllo. È ansible ignorare questo finché si creano i thread da soli. Ma ciò non è pratico per thread e thread threadpool che potrebbero essere stati creati da un qualche tipo di codice non gestito che esegue il processo, come un server COM.

Il secondo caso è il problema. .NET non ha problemi a eseguire codice gestito su thread creati da codice non gestito. Ma non può fare nulla sul modo in cui il thread è inizializzato. Questo è vero per CurrentUICulture ma anche per cose più oscure come Thread.SetApartmentState (). Non sottovalutare la probabilità che un thread di questo tipo esegua codice nel tuo programma, i server COM scritti da Microsoft sono molto felici.

Dovrai versare il codice con un pettine a denti fini e trovare qualsiasi codice che possa essere eseguito su un filo che non hai creato. Qualsiasi gestore di eventi è sospetto, come qualsiasi metodo BeginXxx () che ha un callback. BackgroundWorker è sicuramente il problema minore.

Non sovrascrivere la cultura del thread può produrre bugz molto sottili e difficili da diagnosticare. Un buon esempio sarebbe un SortedList che digita su una stringa. Quando viene eseguito con la cultura sbagliata, casualmente non riuscirà a trovare gli elementi effettivamente presenti nella lista. Causato dall’elenco non più ordinato in un’altra cultura con regole di confronto diverse.

Se sono riuscito a spaventarti abbastanza, ho ricevuto il mio messaggio. Questo è successo a me, facendo il debug di un problema con un programma molto grande che si è comportato male su una macchina danese. Non avevamo una localizzazione danese e abbiamo costretto l’interfaccia utente a girare in inglese. Un thread di lavoro utilizzava un albero rosso-nero che aveva una stringa come chiave. Falliva casualmente quando gli veniva chiesto di trattare con Åårdvårks. Mi ci sono voluti una settimana.


Aggiornamento: questo problema è stato risolto in .NET 4.5. La class CultureInfo ora ha un DefaultThreadCurrentCulture e DefaultThreadCurrentUICulture. Se impostato, verrà utilizzato per inizializzare la cultura di qualsiasi thread gestito anziché la cultura di sistema predefinita di Windows. Il modo in cui interagisce con i thread avviati dal codice nativo e che inserisci codice gestito non mi è ancora chiaro.


Aggiornamento: questo problema ha avuto una soluzione più approfondita in .NET 4.6. La cultura ora scorre automaticamente, il comportamento ideale. L’articolo MSDN per CultureInfo.CurrentCulture () ne parla. Le informazioni fornite sono ancora confuse, sperimentalmente sembra anche che fluisca su un object Thread e non solo su un thread Task o Threadpool e DefaultThreadCurrentCulture non viene utilizzato. Due passi avanti, un passo indietro, si consiglia di testare.

La mia soluzione era di avere una proprietà di cultura centrale (Application.CurrentCulture è per-thread) e impostare la cultura di thread corrente su questo all’inizio di un thread di lavoro. Un sistema di lavoro aiuta in questo modo, dal momento che è ansible eseguire facilmente codice generico prima e dopo l’elemento di lavoro e la class del sistema di lavoro può contenere la cultura accessibile dai suoi lavori, quindi non è necessario disporre di globals.

In poche parole; Non farlo

Non eseguire alcuna formattazione specifica della lingua su un altro thread rispetto al thread principale ( Thread.CurrentThread ). Ottenere la cultura corretta su altri thread – ogni altro thread creato – è solo un dolore e prima o poi ti dimenticherai di impostarlo correttamente. Meglio evitare semplicemente il dolore tutti insieme e solo fare la formattazione specifica per la cultura, la conversione, ecc. Sul thread che si garantisce che sia nelle impostazioni di cultura corrette.

Non puoi farlo per ogni thread appena creato. Dovresti farlo a mano (ma non credo che impostare la cultura per i thread del pool di thread sia una buona idea!). Forse la tua applicazione dovrebbe dipendere da Application.CurrentCulture o qualche altra roba globale ..

Windows inizializza sempre un thread del sistema operativo sull’LCID predefinito del sistema, configurato nell’applet Opzioni internazionali e della lingua nel Pannello di controllo.

Purtroppo non sono d’accordo con questo e ho trovato il contrario.

Il sistema è stato installato come inglese americano. Sono andato al pannello di controllo cambiato tutto in danese e copiato su tutti i conti. Riavviato.

Esegui l’app della console che viene eseguita in danese. Esegui l’app web chiedi al browser che dice danese. Avvia il thread dall’app Web e viene lanciato come gli Stati Uniti non sono danesi e non riesco a capire perché.

So che l’argomento è vecchio ma mi sono trovato in un problema di “thread con la cultura del sistema operativo”.

L’ho risolto così: dato che BackgroundWorker è in un UserControl (sarebbe valido se si trova in un form e così via …) imposto un campo in UserControl (o Form) quando viene costruito. Nel gestore di eventi DoWork utilizzo questo campo nelle mie operazioni. Ecco il codice:

  ///  /// Culture in which the GUI creates the control. ///  private readonly CultureInfo _currentCulture; ///  /// Default constructor. ///  public MyControl() { InitializeComponent(); _currentCulture = CultureInfo.CurrentUICulture; } private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { ExampleClass.DoCultureDependentOperation(_currentCulture); }