Double. TryParse o Convert.ToDouble: ¿cuál es más rápido y seguro?

80

Mi aplicación lee un archivo de Excel usando VSTO y agrega los datos leídos a un archivo StringDictionary. Agrega solo datos que son números con unos pocos dígitos (1000 1000,2 1000,34 - la coma es un delimitador en los estándares rusos).

¿Qué es mejor para verificar si la cadena actual es un número apropiado?

object data, string key; // data had read

try
{
  Convert.ToDouble(regionData, CultureInfo.CurrentCulture);
  dic.Add(key, regionData.ToString());
}
catch (InvalidCastException)
{
  // is not a number
}

o

double d;
string str = data.ToString();
if (Double.TryParse(str, out d)) // if done, then is a number
{
  dic.Add(key, str);
}

Tengo que usarlo en StringDictionarylugar de Dictionary<string, double>debido a los siguientes problemas de algoritmo de análisis.

Mis preguntas: ¿Qué camino es más rápido? ¿Qué es más seguro?

¿Y es mejor llamar Convert.ToDouble(object)o Convert.ToDouble(string)?

abatishchev
fuente
Para su información, double.TryParse es lo mismo que try {result = double.Parse (s); devuelve verdadero; } captura {devuelve falso; }. Convert es esencialmente un contenedor para ambos con un montón de sobrecargas. No importa cómo lo hagas. Pero, como ha señalado Jon, piense en cómo manejar la mala entrada.
John Leidegren
12
Double. TryParse no es lo mismo que double.Parse envuelto en un try..catch. La semántica es la misma, pero la ruta del código es diferente. TryParse primero verifica que la cadena sea un número usando un Number.TryStringToNumber interno, mientras que Parse asume que ya es un número / doble.
Jeff Moser

Respuestas:

131

Hice una prueba rápida no científica en el modo de lanzamiento. Usé dos entradas: "2.34523" y "badinput" en ambos métodos e iteraron 1,000,000 veces.

Entrada válida:

Double.TryParse = 646ms
Convert.ToDouble = 662 ms

No muy diferente, como se esperaba. Para todos los efectos, para una entrada válida, estos son los mismos.

Entrada inválida:

Double.TryParse = 612ms
Convert.ToDouble = ..

Bueno ... estuvo funcionando durante mucho tiempo. Repetí todo usando 1,000 iteraciones y Convert.ToDoublecon una mala entrada tardé 8.3 segundos. Haciendo un promedio, tomaría más de 2 horas. No me importa cuán básica sea la prueba, en el caso de entrada no válida, Convert.ToDoublela activación de excepciones arruinará su rendimiento.

Entonces, aquí hay otro voto a favor TryParsecon algunos números para respaldarlo.

Szymon Rozga
fuente
4
Además de las cosas mencionadas anteriormente, descubrí que Convert.ToDouble () lanzará una excepción con números en notación científica. Considere esto: double toDouble = Convert.ToDouble ((- 1/30000) .ToString ()); // fallará double dblParse = Double.Parse ((- 1/30000) .ToString ()); // funciona bien
Buddy Lee
46

Para empezar, usaría en double.Parselugar de Convert.ToDoubleen primer lugar.

En cuanto a si debe usar Parseo TryParse: ¿puede continuar si hay datos de entrada incorrectos o es una condición realmente excepcional? Si es excepcional, utilícelo Parsey déjelo explotar si la entrada es mala. Si se espera y se puede manipular limpiamente, úselo TryParse.

Jon Skeet
fuente
6
Jon, ¿puedes explicar por qué prefieres double.Parse sobre Convert.ToDouble?
David North
10
@dnorthut: Rara vez quiero que nulo se convierta a 0 (lo que hace Convert.ToDouble), básicamente. También es generalmente más flexible. Solo tiendo a optar por métodos específicos ...
Jon Skeet
8

Las pautas de diseño de .NET Framework recomiendan utilizar los métodos Try. Evitar excepciones suele ser una buena idea.

Convert.ToDouble(object) haré ((IConvertible) object).ToDouble(null);

Que llamará Convert.ToDouble(string, null)

Entonces es más rápido llamar a la versión de cadena.

Sin embargo, la versión de cadena simplemente hace esto:

if (value == null)
{
    return 0.0;
}
return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);

Así que es más rápido hacerlo double.Parsedirectamente.

Jeff Moser
fuente
7

Si no va a manejar la excepción, vaya con TryParse. TryParse es más rápido porque no tiene que lidiar con todo el seguimiento de la pila de excepciones.

Aaron Palmer
fuente
7

Generalmente trato de evitar la Convertclase (es decir, no la uso) porque la encuentro muy confusa: el código da muy pocas pistas sobre lo que sucede exactamente aquí desdeConvert permite que ocurran muchas conversiones semánticamente muy diferentes con el mismo código . Esto dificulta que el programador controle qué está sucediendo exactamente.

Mi consejo, por lo tanto, es que nunca uses esta clase. Tampoco es realmente necesario (excepto para el formato binario de un número, porque el ToStringmétodo normal de clases de números no ofrece un método apropiado para hacer esto).

Konrad Rudolph
fuente
7

A menos que esté 100% seguro de sus entradas, que rara vez es el caso, debe usar Double.TryParse.

Convert.ToDouble will throw an exception on non-numbers
Double.Parse will throw an exception on non-numbers or null
Double.TryParse will return false or 0 on any of the above without generating an exception.

La velocidad del análisis se vuelve secundaria cuando lanza una excepción porque no es mucho más lenta que una excepción.

Persecución
fuente
4

Hay mucho odio por la clase Convert aquí ... Solo para equilibrar un poco, hay una ventaja para Convert: si te entregan un objeto,

Convert.ToDouble(o);

puede devolver el valor fácilmente si o ya es un Double (o un int o cualquier cosa que se pueda lanzar fácilmente).

Usar Double.Parse o Double.TryParse es genial si ya lo tiene en una cadena, pero

Double.Parse(o.ToString());

primero tiene que hacer que la cadena se analice y, dependiendo de su entrada, eso podría ser más costoso.

usuario1664043
fuente
1
+1: veo su punto de vista, analizando números / cadenas en caja con un número dentro de un System.Object es bastante fácil, en lugar de una verificación de tipo masiva. Pero básicamente estoy de acuerdo con otras respuestas: Convert.ToSomething()es mucho más caro que Parse / TryParse, especialmente en un contexto de iteración
T-moty
Para mí, Convert.ToDouble (o) tiene algunas salidas fáciles si lo que hay en la caja ya es un número, pero el verdadero asesino de Convert es que no tiene un. TryToDouble (o, out d); Dado lo caras que son las excepciones (y lo seguro que está, o no, de las entradas), ese es el gran gasto adicional de Convert.
user1664043
2

Double. TryParse IMO.

Es más fácil de manejar para usted, sabrá exactamente dónde ocurrió el error.

Luego, puede manejarlo como mejor le parezca si devuelve falso (es decir, no se pudo convertir).

Damien
fuente
2

Siempre he preferido usar los TryParse()métodos porque va a devolver el éxito o el fracaso en la conversión sin tener que preocuparme por las excepciones.

TheTXI
fuente
2

Ésta es una vieja pregunta interesante. Estoy agregando una respuesta porque nadie notó un par de cosas con la pregunta original.

¿Qué es más rápido: Convert.ToDouble o Double.TryParse? ¿Qué es más seguro: Convert.ToDouble o Double.TryParse?

Voy a responder estas dos preguntas (actualizaré la respuesta más adelante), en detalle, pero primero:

Por seguridad, lo que todos los programadores se perdieron en esta pregunta es la línea (énfasis mío):

Agrega solo datos que son números con unos pocos dígitos (1000 1000,2 1000,34 - la coma es un delimitador en los estándares rusos ).

Seguido por este ejemplo de código:

Convert.ToDouble(regionData, CultureInfo.CurrentCulture);

Lo interesante aquí es que si las hojas de cálculo están en formato numérico ruso pero Excel no ha escrito correctamente los campos de celda, ¿cuál es la interpretación correcta de los valores provenientes de Excel?

Aquí hay otra cosa interesante sobre los dos ejemplos, con respecto a la velocidad:

catch (InvalidCastException)
{
    // is not a number
}

Es probable que esto genere un MSIL con este aspecto:

catch [mscorlib]System.InvalidCastException 
{
  IL_0023:  stloc.0
  IL_0024:  nop
  IL_0025:  ldloc.0
  IL_0026:  nop
  IL_002b:  nop
  IL_002c:  nop
  IL_002d:  leave.s    IL_002f
}  // end handler
IL_002f: nop
IL_0030: return

En este sentido, probablemente podamos comparar el número total de instrucciones MSIL llevadas a cabo por cada programa, más sobre eso más adelante cuando actualice esta publicación.

Creo que el código debe ser correcto, claro y rápido ... ¡ en ese orden!

John Zabroski
fuente
1

Personalmente, encuentro que el TryParsemétodo es más fácil de leer, el que realmente querrá usar depende de su caso de uso: si los errores se pueden manejar localmente, está esperando errores y un bool de TryParsees bueno, de lo contrario, es posible que desee dejar las excepciones vuelan.

Esperaría TryParseque también fuera más rápido, ya que evita la sobrecarga del manejo de excepciones. Pero use una herramienta de referencia, como MiniBench de Jon Skeet para comparar las diversas posibilidades.

David Schmitt
fuente
Comentarios sobre esta respuesta: Si la pregunta pregunta qué es más rápido y seguro, la respuesta no debe comenzar con: "Personalmente" e incluir adivinanzas como: "Yo esperaría ...". Estos son solo pensamientos y comentarios personales, no una buena respuesta.
PandaWood