¿Qué significa CultureInfo.InvariantCulture?

177

Tengo una cadena de texto así:

var foo = "FooBar";

Quiero declarar una segunda cadena llamada bary hacer que sea igual al primer y cuarto carácter de mi primero foo, así que hago esto así:

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

Esto funciona como se esperaba, pero ReSharper me aconseja poner Culture.InvariantCulturedentro de mis corchetes, por lo que esta línea termina así:

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

¿Qué significa esto y afectará la forma en que se ejecuta mi programa?

JMK
fuente
2
Vea esta pregunta SO: stackoverflow.com/questions/8492449/…
msigman
38
Para aquellos que buscan la respuesta de 5 segundos: CultureInfo.InvariantCulture significa "No me importa, no quiero que la cultura esté involucrada en primer lugar. Ahora déjenme usar lo tonto".
Andrew
55
@ Andrew ¿Puedes reescribir todos los documentos de MS, por favor?
Yatrix
3
@Yatrix Sí, claro. ¡Me encantaría! Quien paga
Andrew

Respuestas:

154

No todas las culturas usan el mismo formato para fechas y valores decimales / monetarios.

Esto tendrá importancia para usted cuando usted está convirtiendo valores de entrada (leer) que se almacenan como cadenas a DateTime, float, doubleo decimal. También será importante si intenta formatear los tipos de datos mencionados anteriormente en cadenas (escritura) para su visualización o almacenamiento.

Si sabe en qué cultura específica estarán sus fechas y valores decimales / monetarios antes de tiempo, puede usar esa CultureInfopropiedad específica (es decir CultureInfo("en-GB")). Por ejemplo, si espera una entrada del usuario.

La CultureInfo.InvariantCulturepropiedad se utiliza si está formateando o analizando una cadena que debería ser analizable por un software independiente de la configuración local del usuario.

El valor predeterminado es CultureInfo.InstalledUICulturepor lo que CultureInfo predeterminado depende de la configuración del SO en ejecución. Es por eso que siempre debe asegurarse de que la información cultural se ajuste a su intención (consulte la respuesta de Martin para obtener una buena guía).

JohnB
fuente
3
"en-US", sin embargo, creo que en realidad puede depender de la configuración de su sistema.
Rastreador1
44
El valor predeterminado no lo es en-US. Es la cultura local. Y InvariantCulturese usa cuando desea un formato cultural neutral que sea independiente del sistema local. Por ejemplo, cuando se trabaja con formatos de archivo basados ​​en texto.
CodesInChaos
23
Para agregar al comentario @CodesInChaos: La afirmación de que el valor predeterminado es CultureInfo ("en-US") es simplemente incorrecta. Además, la declaración La propiedad CultureInfo.InvariantCulture se usa cuando no está seguro de antemano en qué formato cultural estarán sus fechas y valores decimales / monetarios. Es confuso. Usar la cultura actual, la invariante o específica es algo que debería ser una decisión consciente, y si te equivocas puedes alienar a tus usuarios (no estadounidenses). No debe usar la cultura invariante si no está seguro. Debe estar seguro de antemano.
Martin Liversage
3
-1 debido a los problemas mencionados en otros comentarios. La respuesta de Martin es más útil porque le dice cuándo usar y no usar cada cultura.
Ed Greaves
"si está trabajando exclusivamente en inglés americano, entonces no necesita preocuparse por eso": Incorrecto, puede estar trabajando exclusivamente en inglés americano, pero el software puede ejecutarse en un "en-GB" o un "de -DE ", entonces hará una diferencia, además puede tomar la cultura del cliente (si lo dice en el archivo web.config), y eso podría no ser" en-US "tampoco ...
Stefan Steiger
151

Cuando los números, las fechas y las horas se formatean en cadenas o se analizan a partir de cadenas, se utiliza una cultura para determinar cómo se hace. Por ejemplo, en la en-UScultura dominante tienes estas representaciones de cuerdas:

  • 1,000,000.00 - un millón con una fracción de dos dígitos
  • 29/01/2013 - fecha de esta publicación

En mi cultura ( da-DK) los valores tienen esta representación de cadena:

  • 1.000.000,00 - un millón con una fracción de dos dígitos
  • 29-01-2013 - fecha de esta publicación

En el sistema operativo Windows, el usuario puede incluso personalizar cómo se formatean los números y las fechas / horas y también puede elegir otra cultura que no sea la cultura de su sistema operativo. El formato utilizado es la elección del usuario, que es cómo debe ser.

Así que cuando se formatea un valor que se muestra al usuario el uso de, por ejemplo, ToStringo String.Formato analizada desde una cadena usando DateTime.Parseo Decimal.Parseel valor por defecto es usar el CultureInfo.CurrentCulture. Esto permite al usuario controlar el formateo.

Sin embargo, una gran cantidad de formato de cadenas y análisis no son cadenas intercambiadas entre la aplicación y el usuario, sino entre la aplicación y algún formato de datos (por ejemplo, un archivo XML o CSV). En ese caso, no desea usarlo CultureInfo.CurrentCultureporque si se formatea y analiza con diferentes culturas, puede romperse. En ese caso, desea utilizar CultureInfo.InvariantCulture(que se basa en la en-UScultura). Esto asegura que los valores pueden ser de ida y vuelta sin problemas.

La razón de que ReSharper le da la advertencia es que algunos programadores de aplicaciones no son conscientes de esta distinción que puede conducir a resultados no deseados pero nunca descubren esto porque sus CultureInfo.CurrentCulturees decir en-US, que tiene el mismo comportamiento que CultureInfo.InvariantCulture. Sin embargo, tan pronto como la aplicación se use en otra cultura donde existe la posibilidad de usar una cultura para formatear y otra para analizar, la aplicación puede romperse.

Para resumirlo:

  • Use CultureInfo.CurrentCulture(el valor predeterminado) si está formateando o analizando una cadena de usuario.
  • Úselo CultureInfo.InvariantCulturesi está formateando o analizando una cadena que debería ser analizable por una pieza de software.
  • Raramente use una cultura nacional específica porque el usuario no puede controlar cómo se realiza el formateo y el análisis.
Martin Liversage
fuente
1
Con respecto al último punto, "Raramente use una cultura nacional específica ...", ¿sería el formato de moneda una excepción? Por ejemplo, si tengo una Decimalvariable que contiene un cierto valor en dólares estadounidenses, ¿me gustaría hacer una excepción y usarla en-UScomo cultura al mostrarla para asegurarme de que no obtengo un resultado que se parece a un número en euros? Lo intenté CultureInfo.InvariantCulture , pero obtuve esto para el marcador de moneda ¤, así que no estoy seguro de que sea la forma correcta.
Jeff B
1
@JeffBridgman: Mi consejo es solo un consejo general y puede no aplicarse a su caso específico. Sin embargo, creo que la forma en que muestra el punto decimal (coma o punto) debería ser algo que el usuario controle (por ejemplo, use CultureInfo.CurrentCulture). Si además de mostrar un número necesita la moneda, entonces quizás debería hacerlo de manera consistente, es decir, sin usar CultureInfoay, en su lugar, use el código de moneda de tres letras como USD 1,234.56. Entonces no te metes en los problemas de asignar una moneda a una cultura.
Martin Liversage
26

De acuerdo con Microsoft:

La propiedad CultureInfo.InvariantCulture no es una cultura neutral ni específica. Es un tercer tipo de cultura que es insensible a la cultura. Está asociado con el idioma inglés pero no con un país o región.

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

Entonces InvariantCulture es similar a la cultura "en-US" pero no exactamente igual. Si tú escribes:

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"

entonces s1 y s2 tendrán un formato similar pero InvariantCulture agrega ceros a la izquierda y "en-US" usa AM o PM.

Entonces InvariantCulture es mejor para uso interno, cuando, por ejemplo, guarda una fecha en un archivo de texto o analiza datos. Y un CultureInfo especificado es mejor cuando presenta datos (fecha, moneda ...) al usuario final.

happybits
fuente
3
Ejecuté su código de ejemplo para confirmar: InvariantCulture usa American MM / dd / aaaa en lugar de seguir el formato ISO 8601 de primer año. A pesar de eso, está destinado al almacenamiento portátil y al procesamiento mecánico, en lugar de al consumo humano. Qué confuso
Max Barraclough
4

Para cosas como números (puntos decimales, comas en cantidades), generalmente se prefieren en la cultura específica.

Una forma adecuada de hacerlo sería establecerlo en el nivel de cultura (para alemán) de esta manera:

Thread.CurrentThread.CurrentCulture.NumberFormat = new CultureInfo("de").NumberFormat;
Máquina de Turing
fuente
4

JetBrains ofrece una explicación razonable ,

"La conversión ad-hoc de estructuras de datos a texto depende en gran medida de la cultura actual, y puede conducir a resultados no deseados cuando el código se ejecuta en una máquina cuya configuración local difiere de la del desarrollador original. Para evitar ambigüedades, ReSharper le advierte de cualquier instancia en el código donde tal problema pueda ocurrir ".

pero si estoy trabajando en un sitio que sé que solo estará en inglés, simplemente ignoro la sugerencia.

Neil Thompson
fuente