Co oznacza CultureInfo.InvariantCulture?

177

Mam taki ciąg tekstu:

var foo = "FooBar";

Chcę zadeklarować drugi wywołany ciąg bari uczynić go równym pierwszemu i czwartemu znakowi mojego pierwszego foo, więc robię to w ten sposób:

var bar = foo[0].ToString() + foo[3].ToString();

Działa to zgodnie z oczekiwaniami, ale ReSharper radzi mi umieścić Culture.InvariantCulturew nawiasach, więc ta linia kończy się tak:

var bar = foo[0].ToString(CultureInfo.InvariantCulture)
        + foo[3].ToString(CultureInfo.InvariantCulture);

Co to oznacza i czy wpłynie na sposób działania mojego programu?

JMK
źródło
2
Zobacz to pytanie SO: stackoverflow.com/questions/8492449/ ...
msigman
38
Dla tych, którzy szukają odpowiedzi na pięć sekund: CultureInfo.InvariantCulture oznacza „Nie obchodzi mnie to, nie chcę, aby kultura była zaangażowana w pierwszej kolejności. Teraz pozwólcie mi użyć głupiej rzeczy”.
Andrew,
5
@ Andrew Czy możesz przepisać wszystkie dokumenty MS, proszę?
Yatrix
3
@Yatrix Yeah, jasne. Z przyjemnością! Kto płaci?
Andrew,

Odpowiedzi:

154

Nie wszystkie kultury używają tego samego formatu dat i wartości dziesiętnych / walutowych.

Będzie to ważne dla ciebie, gdy jesteś przeliczania wartości wejściowych (odczyt) , które są przechowywane jako ciągi do DateTime, float, doublelub decimal. Będzie miało również znaczenie, jeśli spróbujesz sformatować wyżej wymienione typy danych na ciągi (zapis) do wyświetlania lub przechowywania.

Jeśli wiesz z wyprzedzeniem, jaka konkretna kultura, w której będą obowiązywały Twoje daty i wartości dziesiętne / walutowe, możesz użyć tej określonej CultureInfowłaściwości (tj CultureInfo("en-GB").). Na przykład, jeśli oczekujesz danych wejściowych użytkownika.

CultureInfo.InvariantCultureWłaściwość jest używana, jeśli formatowanie lub parsowania ciąg znaków, który powinien być parsowalnym przez kawałek oprogramowania, niezależnie od ustawień lokalnych użytkownika.

Wartość domyślna to, CultureInfo.InstalledUICulturewięc domyślna CultureInfo zależy od ustawień wykonywanego systemu operacyjnego. Dlatego zawsze powinieneś upewnić się, że informacje o kulturze pasują do twoich zamiarów (zobacz odpowiedź Martina, aby uzyskać dobrą wskazówkę).

JohnB
źródło
3
„en-US” myślę jednak, że może to zależeć od ustawień systemu.
Tracker1
44
Wartość domyślna to nie en-US. To lokalna kultura. I InvariantCulturejest używany, gdy chcesz mieć neutralne kulturowo formatowanie, które jest niezależne od systemu lokalnego. Na przykład podczas pracy z formatami plików opartymi na tekście.
CodesInChaos
23
Aby dodać do komentarza @CodesInChaos: Twierdzenie, że wartością domyślną jest CultureInfo („en-US”) jest po prostu błędne. Ponadto instrukcja Właściwość CultureInfo.InvariantCulture jest używana, gdy nie masz pewności z wyprzedzeniem, w jakim formacie kultury będą znajdować się daty i wartości dziesiętne / walutowe. Jest mylące. Korzystanie z aktualnej, niezmiennej lub określonej kultury to coś, co powinno być świadomą decyzją, a jeśli popełnisz błąd, możesz zrazić swoich (spoza USA) użytkowników. Nie powinieneś używać niezmiennej kultury, jeśli nie masz pewności. Musisz być pewien z wyprzedzeniem.
Martin Liversage,
3
-1 ze względu na kwestie poruszone w innych komentarzach. Odpowiedź Martina jest bardziej pomocna, ponieważ mówi ci, kiedy używać, a kiedy nie używać poszczególnych kultur.
Ed Greaves,
„jeśli pracujesz wyłącznie w amerykańskim języku angielskim, nie musisz się tym martwić.”: Niepoprawnie, możesz pracować wyłącznie w amerykańskim języku angielskim, ale oprogramowanie może działać na „en-GB” lub „de -DE ", to zrobi różnicę, a dodatkowo może przyjąć kulturę klienta (jeśli tak mówisz w pliku web.config), i to też może nie być" en-US "...
Stefan Steiger
151

Gdy liczby, daty i godziny są formatowane w ciągi lub analizowane z ciągów, do określenia, jak to się robi, używana jest kultura. Na przykład w en-USkulturze dominującej masz następujące reprezentacje ciągów:

  • 1000000,00 - milion z dwucyfrowym ułamkiem
  • 29.01.2013 - data publikacji

W mojej kulturze ( da-DK) wartości mają następującą reprezentację ciągu:

  • 1.000.000,00 - milion z dwucyfrową częścią
  • 29-01-2013 - data tego nadania

W systemie operacyjnym Windows użytkownik może nawet dostosować formatowanie liczb i daty / czasu, a także może wybrać inną kulturę niż kultura jego systemu operacyjnego. Użyte formatowanie to wybór użytkownika, jaki powinien być.

Dlatego podczas formatowania wartości, która ma być wyświetlana użytkownikowi, za pomocą na przykład ToStringlub String.Formatlub przeanalizowanej z ciągu przy użyciu DateTime.Parselub, Decimal.Parsedomyślnie jest używana CultureInfo.CurrentCulture. Pozwala to użytkownikowi kontrolować formatowanie.

Jednak wiele formatowania i parsowania ciągów nie jest w rzeczywistości ciągami wymienianymi między aplikacją a użytkownikiem, ale między aplikacją a jakimś formatem danych (np. Plikiem XML lub CSV). W takim przypadku nie chcesz używać, CultureInfo.CurrentCultureponieważ jeśli formatowanie i analizowanie są wykonywane z różnymi kulturami, może się zepsuć. W takim przypadku chcesz użyć CultureInfo.InvariantCulture(który jest oparty na en-USkulturze). Dzięki temu wartości mogą być przesyłane w obie strony bez problemów.

Powodem, dla którego ReSharper ostrzega Cię, jest to, że niektórzy autorzy aplikacji nie są świadomi tego rozróżnienia, które może prowadzić do niezamierzonych wyników, ale nigdy tego nie odkryją, ponieważ ich zachowanie CultureInfo.CurrentCulturejest en-UStakie samo jak CultureInfo.InvariantCulture. Jednak gdy tylko aplikacja zostanie użyta w innej kulturze, w której istnieje możliwość użycia jednej kultury do formatowania, a innej do analizowania, aplikacja może się zepsuć.

Podsumowując:

  • Użyj CultureInfo.CurrentCulture(wartość domyślna), jeśli formatujesz lub analizujesz ciąg użytkownika.
  • Użyj, CultureInfo.InvariantCulturejeśli formatujesz lub analizujesz ciąg, który powinien być analizowany przez oprogramowanie.
  • Rzadko używaj określonej kultury narodowej, ponieważ użytkownik nie może kontrolować sposobu formatowania i analizowania.
Martin Liversage
źródło
1
Jeśli chodzi o ostatni punkt, „Rzadko używaj określonej kultury narodowej…”, czy formatowanie waluty byłoby wyjątkiem? Na przykład, jeśli mam Decimalzmienną zawierającą określoną wartość w dolarach amerykańskich, czy chciałbym zrobić wyjątek i użyć go en-USjako kultury podczas wyświetlania, aby upewnić się, że nie otrzymam wyniku, który wygląda jak liczba w euro? Próbowałem CultureInfo.InvariantCulture , ale mam to dla znacznika waluty ¤, więc nie jestem pewien, czy to właściwy sposób.
Jeff B,
1
@JeffBridgman: Moja rada to tylko ogólna rada i może nie mieć zastosowania w Twoim konkretnym przypadku. Myślę jednak, że sposób wyświetlania kropki dziesiętnej (przecinek lub kropka) powinien być czymś, co użytkownik kontroluje (np. Używa CultureInfo.CurrentCulture). Jeśli oprócz wyświetlania liczby potrzebujesz waluty, być może powinieneś to zrobić w spójny sposób, tj. Nie używając CultureInfoa zamiast tego użyj trzyliterowego kodu waluty, takiego jak USD 1,234.56. Wtedy nie będziesz mieć problemów z mapowaniem waluty na kulturę.
Martin Liversage,
26

Według Microsoft:

Właściwość CultureInfo.InvariantCulture nie jest kulturą neutralną ani określoną. Jest to trzeci typ kultury niewrażliwy na kulturę. Jest powiązany z językiem angielskim, ale nie z krajem lub regionem.

(z http://msdn.microsoft.com/en-us/library/4c5zdc6a(vs.71).aspx )

Tak więc InvariantCulture jest podobna do kultury „en-US”, ale nie jest dokładnie taka sama. Jeśli napiszesz:

var d = DateTime.Now;
var s1 = d.ToString(CultureInfo.InvariantCulture);   // "05/21/2014 22:09:28"
var s2 = d.ToString(new CultureInfo("en-US"));       // "5/21/2014 10:09:28 PM"

wtedy s1 i s2 będą miały podobny format, ale InvariantCulture dodaje zera wiodące, a „en-US” używa AM lub PM.

Tak więc InvariantCulture jest lepsza do użytku wewnętrznego, kiedy np. Zapisujesz datę do pliku tekstowego lub analizujesz dane. A określony CultureInfo jest lepszy, gdy przedstawiasz dane (datę, walutę ...) użytkownikowi końcowemu.

happybits
źródło
3
Uruchomiłem Twój przykładowy kod, aby potwierdzić: InvariantCulture używa amerykańskiego formatu MM / dd / rrrr, zamiast postępować zgodnie z formatem ISO 8601 rok pierwszy. Mimo to jest przeznaczony do przenośnego przechowywania i obróbki mechanicznej, a nie do spożycia przez ludzi. Jakie to zagmatwane
Max Barraclough
4

W przypadku liczb (kropki dziesiętne, przecinki w kwotach) są one zwykle preferowane w określonej kulturze.

Odpowiednim sposobem na zrobienie tego byłoby ustawienie go na poziomie kultury (dla języka niemieckiego) w następujący sposób:

Thread.CurrentThread.CurrentCulture.NumberFormat = new CultureInfo("de").NumberFormat;
Maszyna Turinga
źródło
4

JetBrains oferuje rozsądne wyjaśnienie ,

„Konwersja ad-hoc struktur danych na tekst jest w dużej mierze zależna od aktualnej kultury i może prowadzić do niezamierzonych rezultatów, gdy kod jest wykonywany na maszynie, której ustawienia regionalne różnią się od ustawień oryginalnego programisty. Aby zapobiec niejasności, ReSharper ostrzega przed wszelkie przypadki w kodzie, w których może wystąpić taki problem ”.

ale jeśli pracuję w witrynie, o której wiem, że będzie tylko w języku angielskim, po prostu ignoruję sugestię.

Neil Thompson
źródło