CultureInfo zawiera informacje regionalne, przydatne, jeśli chcemy dostosować naszą aplikację do różnym krajów. Używamy tej klasy m.in. do określenia formatowania liczb, dat czy po prostu języka w jakim wyświetlamy tekst.
Jeśli korzystamy z domyślnych ustawień regionalnych, wtedy poniższy kod wyświetli prawidłową wartość CultureInfo:
static void Main(string[] args) { DisplayCulture(); Task.Factory.StartNew(DisplayCulture); Console.ReadLine(); } private static void DisplayCulture() { Console.WriteLine(CultureInfo.CurrentCulture.ToString()); }
Często jednak w aplikacji można zmienić język i tym samym CultureInfoUI. Nierzadko popełnianym błędem jest po prostu ustawienie CultureInfo dla aktualnego wątku:
class Program { static void Main(string[] args) { Thread.CurrentThread.CurrentCulture=new CultureInfo("en-US"); DisplayCulture(); Task.Factory.StartNew(DisplayCulture); Console.ReadLine(); } private static void DisplayCulture() { Console.WriteLine(Thread.CurrentThread.CurrentCulture); } }
Kod zmienia kulturę wyłącznie aktualnego wątku – w tym przypadku głównego. Wszelkie inne wątki, będą używały kultury domyślnej z ustawień regionalnych. W celu zsynchronizowania wątków musimy sami przekazywać kulturę i ustawiać ją ręcznie w każdym z wątków.
Jest to dość czasochłonne i nudne zajęcie więc istnieją pewne usprawnienia od .NET 4.5:
class Program { static void Main(string[] args) { CultureInfo.DefaultThreadCurrentCulture=new CultureInfo("en-US"); DisplayCulture(); Task.Factory.StartNew(DisplayCulture); Console.ReadLine(); } private static void DisplayCulture() { Console.WriteLine(Thread.CurrentThread.CurrentCulture); } }
W .NET 4.5 dodano DefaultThreadCurrentCulture. Ustawienie tej właściwości spowoduje, że wszelkie wątki będą korzystały ze wskazanej kultury. Przed .NET 4.5 trzeba było ręcznie to ustawiać albo zastosować hack, który znajdziecie tutaj:
http://blog.rastating.com/setting-default-currentculture-in-all-versions-of-net/
Kod:
public void SetDefaultCulture(CultureInfo culture) { Type type = typeof(CultureInfo); try { type.InvokeMember("s_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); type.InvokeMember("s_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); } catch { } try { type.InvokeMember("m_userDefaultCulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); type.InvokeMember("m_userDefaultUICulture", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static, null, culture, new object[] { culture }); } catch { } }
Warto zwrócić na to uwagę, ponieważ wyświetlanie np. dat w wątku głównym w inny sposób niż w pozostałych wątkach, nie jest dobrym pomysłem.
Co prawda miałem do tego celu własny statyczny wrapper dla Threads i ThreadPool, ale teraz on mi się bardzo uprościł.