2009-02-25 38 views
74

Mi aplicación lee un archivo de Excel utilizando VSTO y agrega los datos leídos a StringDictionary. Agrega solo datos que son números con algunos dígitos (1000 1000,2 1000,34 - la coma es un delimitador en los estándares rusos).Double.TryParse o Convert.ToDouble - ¿Qué es más rápido y más seguro?

¿Qué es mejor comprobar 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 usar en lugar de StringDictionaryDictionary<string, double> debido a las siguientes cuestiones algoritmo de análisis sintáctico.

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

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

+0

FYI, double.TryParse es lo mismo que try {result = double.Parse (s); devolver verdadero; } catch {return false; }. 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 las malas entradas. –

+10

Doble.TryParse no es lo mismo que double.Parse envuelto en una 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 que usa un Number.TryStringToNumber interno, mientras que Parse asume que ya es un número/doble. –

Respuesta

125

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 iteración 1,000,000 de 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.

de entrada no válido:

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

Bueno .. que estaba funcionando durante mucho tiempo. Volví a usar todo el proceso usando 1,000 iteraciones y Convert.ToDouble con una mala entrada de 8.3 segundos. Promediando, tomaría más de 2 horas. No me importa qué tan básica es la prueba, en el caso de entrada no válida, el aumento de la excepción Convert.ToDouble arruinará su rendimiento.

Así que, aquí hay otra votación para TryParse con algunos números para respaldarlo.

+4

Además de las cosas mencionadas anteriormente, acabo de encontrar 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 –

7

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

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

que llamará Convert.ToDouble(string, null)

Así que es más rápido para llamar a la versión de cadena.

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

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

Por lo tanto, es más rápido para hacer el double.Parse directamente.

2

Double.TryParse IMO.

Es más fácil de manejar, sabrá exactamente dónde se produjo el error.

A continuación, puede tratar con él como mejor le parezca si devuelve falso (es decir, no se pudo convertir).

7

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

7

por lo general tratan de evitar la clase Convert (que significa: Yo no lo uso) porque me resulta muy confuso: el código da muy pocas pistas sobre qué es exactamente lo que sucede aquí desde Convert permite una gran cantidad de semánticamente muy diferentes conversiones ocurrir con el mismo código Esto hace que sea difícil controlar para el programador lo que está sucediendo exactamente.

Mi consejo, por lo tanto, es nunca utilizar esta clase. Tampoco es realmente necesario (a excepción del formato binario de un número, porque el método ToString normal de las clases numéricas no ofrece un método apropiado para hacerlo).

2

Siempre he preferido usar los métodos TryParse() porque va a devolver el éxito o no convertir sin tener que preocuparse por las excepciones.

43

Para empezar, usaría double.Parse en lugar de Convert.ToDouble en primer lugar.

En cuanto a si debe usar Parse o TryParse: ¿puede continuar si hay datos de entrada incorrectos, o es realmente una condición excepcional? Si es excepcional, use Parse y déjelo explotar si la entrada es incorrecta. Si se espera y se puede manejar limpiamente, use TryParse.

+5

Jon, ¿Puedes explicar por qué prefieres el doble? ¿Tocas más de Convert.ToDouble? –

+10

@dnorthut: rara vez quiero que null se convierta a 0 (que Convert.ToDouble lo hace), básicamente. También es generalmente más flexible. Me inclino por los métodos específicos ... –

1

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

Espero que el TryParse sea más rápido también, ya que evita la sobrecarga del manejo de excepciones. Pero use una herramienta de referencia, como Jon Skeet's MiniBench para comparar las diversas posibilidades.

+0

Comentarios sobre esta respuesta: Si las preguntas son más rápidas y seguras, la respuesta no debería comenzar con: "Personalmente" e incluir adivinar como: "Me gustaría ... ". Esto es solo pensamientos y comentarios personales, no una buena respuesta. – PandaWood

7

A menos que esté 100% seguro de sus entradas, lo 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 sintáctico se vuelve secundario cuando se lanza una excepción, ya que no es mucho más lento que una excepción.

3

Un montón de odio de la clase Convert aquí ... sólo para equilibrar un poco, hay una ventaja para convertir - si se le entregó un objeto,

Convert.ToDouble(o); 

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

usando Double.Parse o Double.TryParse es grande si ya lo tienes en una cadena, pero

Double.Parse(o.ToString()); 

tiene que ir a hacer la cadena a analizar primero y dependiendo de su entrada que pudiera ser más caro

+0

+1: veo tu punto de vista, analizando números/cadenas encasilladas con un número dentro de un System.Object es bastante fácil, en lugar de una verificación masiva de tipos. 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 –

+0

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 para Convert es que no tiene .TryToDouble (o, out d); Teniendo en cuenta lo costosas que son las excepciones (y la confianza que tiene (o no) en las entradas), ese es el gran gasto adicional de Convert. – user1664043

Cuestiones relacionadas