2010-01-19 10 views
9

Esta línea de código:Número analizar el Curiosidad

Console.WriteLine(Convert.ToInt32(“23,23”) + 1); 

se produce una excepción. Esta línea de código:

Console.WriteLine(Convert.ToDouble(“23,23”) + 1); 

imprime 2324.

¿Alguien sabe por qué esto es así? No creo que nada bueno pueda venir de la segunda conversión.

+4

Lo cual viene a demostrar que se debe utilizar la sobrecarga que toma NumberStyles y un IFormatProvider si se quiere evitar sorpresas. – bdukes

Respuesta

14

De the MSDN documentation of System.Double.Parse:

El parámetro s puede contener [...] una cadena de la forma:

[ws][sign][integral-digits[,]]integral-digits[.[fractional-digits]][e[sign]exponential-digits][ws]

Aquí, la coma (,) significa " [a] símbolo separador de miles específico de cultura ".

En resumen: si el símbolo separador de miles de su cultura actual aparece en cualquier lugar de la cadena, es ignorado por Double.Parse (invocado internamente por Convert.ToDouble).


Int32.Parse(string), por otro lado, no permite separadores de miles en la cadena:

por lo que su primer ejemplo se produce una excepción. Puede cambiar este comportamiento para Double.Parse y Int32.Parse utilizando una sobrecarga que le permita especificar NumberStyles, como se explica en las otras respuestas.

+0

¿Pero por qué es diferente para 'Integer.Parse'? ¿Los separadores de miles no tienen el mismo sentido aquí? –

+0

@Konrad: actualicé mi respuesta. Int32.Parse solo permite dígitos '[ws] [signo] [ws]'. Acerca de la motivación detrás de esto: No tengo idea ... – Heinzi

+1

Supongo que es solo una diferencia de implementación (que puede o no tener algún fundamento detrás de esto). La documentación de MSDN dice que 'Int32.Parse' solo acepta dígitos' [ws] [sign] [ws] 'donde' ws' es un espacio en blanco. No acepta un operador de miles por defecto ... – bdukes

0

Porque el doble supone que la coma es un separador de miles, y lo ignora. El Int32 Convert no hace eso.

8

La primera falla porque int.Parse no permite el separador de miles de forma predeterminada. Puede cambiar esto usando NumberStyles:

int d = int.Parse("11,23", 
        NumberStyles.AllowThousands, 
        CultureInfo.InvariantCulture); 

Ahora funciona como la versión doble, que hace apoyo separadores de miles por defecto. Presumiblemente tienen éxito porque "," cuando el analizador lo trata como un separador de miles, se ignora por completo, aunque la coma a veces no tiene sentido como separador de miles.

Sorprendentemente, incluso este funciona:

double d = double.Parse("1,,1,2,3", CultureInfo.InvariantCulture); 

En lo anterior, d se establece en el valor 1123,0.

+0

+1 para la sobrecarga con NumberStyles. – Heinzi

+0

+1 para la información útil :) –

+0

Dado que solo hay dos dígitos después del ',' en la muestra provista, ¿no es más probable que sea un separador decimal? –

1

Las comas se ignoran en la conversión a doble. Si desea que las comas generen un error, puede usar el método Double.Parse (cadena, System.Globalization.NumberStyles).

+0

Si la coma (separador de grupos de números) se coloca después del punto decimal, da una excepción de formato, así que supongo que no se ignora, pero se considera de alguna manera. – Keugyeol

6
Console.WriteLine(Convert.ToDouble(“23,23”) + 1); 

En este caso, la coma se interpreta como símbolo separador de grupo de su localización, y se ignora. Ver http://msdn.microsoft.com/en-us/library/fd84bdyt.aspx.

Console.WriteLine(Convert.ToInt32(“23,23”) + 1); 

En este caso, está utilizando Int32.Parse, que no soporta los separadores de grupo por defecto.

El razonamiento detrás de esto es que el convertidor de número entero no tiene soporte de localización por defecto , debido a la localización añade una sobrecarga adicional y no hay ninguna razón para agregarlo a un analizador que no necesita interactuar con cualquier símbolo en todas. Puede, sin embargo, obligar al analizador para apoyar la localización con algunos argumentos adicionales:

int.Parse("11,23", NumberStyles.AllowThousands, CultureInfo.InvariantCulture); 

flotador/doble conversión, por el contrario, tienen para apoyar un separador decimal. En algunas culturas, esto es ",", en otros, puede ser " " o ".". Como la función debe admitir la localización de todos modos, no tendría sentido que solo admita algunas características de localización de forma predeterminada. De lo contrario, la implementación podría confundir a las personas que esperan que, dado que la localización es compatible con el separador decimal, también sería compatible con otros aspectos de localización.

+0

int.Parse * does * admite el separador de miles - ver mi respuesta. –

+0

+1 para la explicación del razonamiento! Es posible que desee escribir "... el convertidor entero * predeterminado * ...", ya que 'Int32.Parse (cadena, Estilos de número)' le permite agregar soporte de localización. – Heinzi

+0

Corregido, gracias. –

0
?double.Parse("23,23", System.Globalization.CultureInfo.InstalledUICulture); 
23.23 

?double.Parse("23,23", new System.Globalization.CultureInfo("en-US")); 
2323.0 
?double.Parse("23,23", new System.Globalization.CultureInfo("fr-FR")); 
23.23 

?double.Parse("23,23", System.Globalization.CultureInfo.InvariantCulture); 
2323.0 

lo mismo para Convert.ToDouble:

?Convert.ToDouble("23,23", System.Globalization.CultureInfo.InvariantCulture); 
2323.0 
Cuestiones relacionadas