Mon application lit un fichier Excel à l'aide de VSTO et ajoute les données lues à un fichier StringDictionary
. Il ajoute uniquement les données qui sont des nombres avec quelques chiffres (1000 1000,2 1000,34 - la virgule est un séparateur selon les normes russes).
Quoi de mieux pour vérifier si la chaîne en cours est un nombre approprié?
object data, string key; // data had read
try
{
Convert.ToDouble(regionData, CultureInfo.CurrentCulture);
dic.Add(key, regionData.ToString());
}
catch (InvalidCastException)
{
// is not a number
}
ou
double d;
string str = data.ToString();
if (Double.TryParse(str, out d)) // if done, then is a number
{
dic.Add(key, str);
}
Je dois utiliser StringDictionary
au lieu de Dictionary<string, double>
À cause des problèmes d'algorithme d'analyse suivants.
Mes questions: quel chemin est plus rapide? Lequel est le plus sûr?
Et est-il préférable d'appeler Convert.ToDouble(object)
ou Convert.ToDouble(string)
?
J'ai fait un test rapide non scientifique en mode Release. J'ai utilisé deux entrées: "2.34523" et "badinput" dans les deux méthodes et itéré 1 000 000 fois.
Entrée valide:
Double.TryParse = 646ms
Convert.ToDouble = 662 ms
Pas très différent, comme prévu. À toutes fins utiles, pour une entrée valide, ce sont les mêmes.
Entrée invalide:
Double.TryParse = 612ms
Convert.ToDouble = ..
Eh bien… ça faisait longtemps que ça fonctionnait. J'ai tout répété en utilisant 1 000 itérations et Convert.ToDouble
Avec une mauvaise entrée prenait 8,3 secondes. En moyenne, cela prendrait plus de 2 heures. Peu m'importe le niveau de base du test, dans le cas d'une entrée invalide, la levée de l'exception de Convert.ToDouble
Ruinera votre performance.
Donc, voici un autre vote pour TryParse
avec quelques chiffres pour le sauvegarder.
Pour commencer, j'utiliserais double.Parse
plutôt que Convert.ToDouble
en premier lieu.
Pour savoir si vous devez utiliser Parse
ou TryParse
: pouvez-vous poursuivre s'il y a de mauvaises données d'entrée, ou s'agit-il d'une condition vraiment exceptionnelle? Si c'est exceptionnel, utilisez Parse
et laissez-le exploser si l'entrée est mauvaise. Si c'est prévu et qu'il peut être manipulé proprement, utilisez TryParse
.
Les instructions de conception du .NET Framework recommandent l’utilisation des méthodes Try. Éviter les exceptions est généralement une bonne idée.
Convert.ToDouble(object)
fera ((IConvertible) object).ToDouble(null);
Qui appellera Convert.ToDouble(string, null)
Il est donc plus rapide d'appeler la version chaîne.
Cependant, la version de chaîne ne fait que ceci:
if (value == null)
{
return 0.0;
}
return double.Parse(value, NumberStyles.Float | NumberStyles.AllowThousands, provider);
Il est donc plus rapide de faire le double.Parse
Directement.
Sauf si vous êtes certain à 100% de vos entrées, ce qui est rarement le cas, vous devez utiliser 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 vitesse de l'analyse devient secondaire lorsque vous générez une exception car il n'y a pas beaucoup plus lent qu'une exception.
Si vous ne gérez pas l'exception, utilisez TryParse. TryParse est plus rapide car il n’a pas à traiter toute la trace de la pile des exceptions.
J'essaie généralement d'éviter la classe Convert
(ce qui signifie: je ne l'utilise pas) parce que je trouve cela très déroutant: le code donne trop peu d'indices sur ce qui se passe exactement ici puisque Convert
permet beaucoup de conversions sémantiquement très différentes se produisent avec le même code. Cela rend difficile de contrôler pour le programmeur ce qui se passe exactement.
Mon conseil est donc de ne jamais utiliser cette classe. Ce n'est pas vraiment nécessaire non plus (sauf pour le formatage binaire d'un nombre, car la méthode normale ToString
des classes de nombres n'offre pas de méthode appropriée pour cela).
Beaucoup de haine pour la classe Convert ici ... Juste pour équilibrer un peu, il y a un avantage pour Convert - si on vous donne un objet,
Convert.ToDouble(o);
peut simplement renvoyer la valeur si o est déjà un Double (ou un int ou quoi que ce soit facilement convertible).
Utiliser Double.Parse ou Double.TryParse est idéal si vous l’avez déjà dans une chaîne, mais
Double.Parse(o.ToString());
doit être make la chaîne à analyser en premier et, en fonction de votre saisie, cela pourrait coûter plus cher.
Double.TryParse IMO.
Il est plus facile pour vous de gérer, vous saurez exactement où l'erreur s'est produite.
Ensuite, vous pouvez gérer la situation de votre choix si elle renvoie false (c’est-à-dire qu’elle ne peut pas convertir).
J'ai toujours préféré utiliser les méthodes TryParse()
parce que cela va générer des succès ou des échecs de conversion sans avoir à se soucier des exceptions.
C'est une vieille question intéressante. J'ajoute une réponse car personne n'a remarqué deux choses dans la question initiale.
Quel est le plus rapide: Convert.ToDouble ou Double.TryParse? Lequel est le plus sûr: Convert.ToDouble ou Double.TryParse?
Je vais répondre à ces deux questions (je mettrai à jour la réponse plus tard), en détail, mais d'abord:
Pour la sécurité, la chose que chaque programmeur a ratée dans cette question est la ligne (l'emphase mienne):
Il ajoute uniquement les données qui sont des nombres avec quelques chiffres (1000 1000,2 1000,34 - la virgule est un séparateur dans les normes russes).
Suivi de cet exemple de code:
Convert.ToDouble(regionData, CultureInfo.CurrentCulture);
Ce qui est intéressant ici, c'est que si les feuilles de calcul sont au format russe mais que Excel n'a pas correctement saisi les champs de cellule, quelle est l'interprétation correcte des valeurs provenant d'Excel?
Voici une autre chose intéressante à propos des deux exemples, concernant la vitesse:
catch (InvalidCastException)
{
// is not a number
}
Cela va probablement générer MSIL qui ressemble à ceci:
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
Dans ce sens, nous pouvons probablement comparer le nombre total d'instructions MSIL effectuées par chaque programme - nous en parlerons plus tard au fur et à mesure que je mettrai à jour ce post.
Je crois que le code devrait être correct, clair et rapide ... Dans cet ordre!
Personnellement, je trouve la méthode TryParse
plus facile à lire, celle que vous voudrez réellement utiliser dépend de votre cas d'utilisation: si les erreurs peuvent être gérées localement, vous attendez des erreurs et une valeur bool de TryParse
est bon, sinon vous voudrez peut-être laisser les exceptions voler.
Je m'attendrais à ce que TryParse
soit également plus rapide, car il évite les frais généraux liés à la gestion des exceptions. Mais utilisez un outil de référence, comme MiniBench de Jon Skeet pour comparer les différentes possibilités.