Double.TryParse або Convert.ToDouble - що швидше і безпечніше?


80

Моя програма читає файл Excel за допомогою VSTO і додає дані прочитаного до StringDictionary. Він додає лише дані, що є числами з кількома цифрами (1000 1000,2 1000,34 - кома є роздільником у російських стандартах).

Що краще перевірити, чи поточний рядок є відповідним числом?

object data, string key; // data had read

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

або

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

Я повинен використовувати StringDictionaryзамість цього Dictionary<string, double>через наступні проблеми алгоритму аналізу.

Мої запитання: Який шлях швидший? Що безпечніше?

А краще зателефонувати Convert.ToDouble(object)чи Convert.ToDouble(string)?


FYI, double.TryParse - це те саме, що try {result = double.Parse (s); повернути істинно; } catch {return false; }. Convert - це, по суті, обгортка для обох із купою перевантажень. Немає різниці, як ви це робите. Але, як зазначав Джон, подумайте, як поводитися з поганими даними.
Джон Лейдегрен,

12
Double.TryParse - це не те саме, що double.Parse, загорнуте в try..catch. Семантика однакова, але шлях коду інший. TryParse спочатку перевіряє, що рядок є числом, використовуючи внутрішній Number.TryStringToNumber, тоді як Parse припускає, що це вже число / подвійне.
Джефф Мозер,

Відповіді:


131

Я провів швидкий ненауковий тест у режимі звільнення. Я використав два входи: "2.34523" і "badinput" для обох методів і повторив 1 000 000 разів.

Дійсне введення:

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

Не сильно відрізняється, як очікувалося. Для всіх намірів і цілей, для дійсного введення вони однакові.

Неправильні дані:

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

Ну .. це тривало довго. Я повторив все, використовуючи 1000 ітерацій, і Convert.ToDoubleз поганим введенням зайняв 8,3 секунди. В середньому це зайняло б більше 2 годин. Мені байдуже, наскільки базовим є тест, у випадку недійсного введення Convert.ToDoubleпідняття винятків зіпсує вашу продуктивність.

Отже, ось ще один голос за TryParseз кількома цифрами, щоб підтвердити це.


4
На додаток до вищезазначених речей, я щойно виявив, що Convert.ToDouble () видасть виняток із числами в наукових позначеннях. Розглянемо це: double toDouble = Convert.ToDouble ((- 1/30000) .ToString ()); // не вдасться подвоїти dblParse = Double.Parse ((- 1/30000) .ToString ()); // працює нормально
Бадді Лі

46

Для початку я б скористався, double.Parseа не Convert.ToDoubleспочатку.

Щодо того, чи слід вам використовувати, Parseабо TryParse: чи можете ви продовжити, якщо є вхідні дані погані, чи це справді виняткова умова? Якщо це виняткове, використовуйте Parseі дайте йому підірватися, якщо вхід поганий. Якщо це очікується і з вами можна чисто поводитися, використовуйте TryParse.


6
Джон, ти можеш детальніше розповісти, чому ти віддаєш перевагу double.Parse замість Convert.ToDouble?
Девід Норт,

10
@dnorthut: Я рідко хочу, щоб null було перетворено в 0 (що Convert.ToDouble робить), в основному. Це також, як правило, більш гнучко. Я просто схиляюся до конкретних методів ...
Джон Скіт,

8

Рекомендації щодо розробки .NET Framework рекомендують використовувати методи Try. Уникнення винятків, як правило, є гарною ідеєю.

Convert.ToDouble(object) зроблю ((IConvertible) object).ToDouble(null);

Який подзвонить Convert.ToDouble(string, null)

Тому швидше викликати рядок.

Однак версія рядка просто робить це:

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

Тож швидше зробити double.Parseбезпосередньо.


7

Якщо ви не збираєтеся обробляти виняток, скористайтеся TryParse. TryParse працює швидше, оскільки йому не потрібно мати справу з усією трасою стеку винятків.


7

Як правило, я намагаюся уникати Convertкласу (мається на увазі: я його не використовую), тому що я вважаю це дуже заплутаним: код дає занадто мало натяків на те, що саме тут відбувається, оскільки Convertдозволяє виконувати багато семантично дуже різних перетворень з одним і тим же кодом . Це ускладнює контроль програміста, що саме відбувається.

Тому моя порада - ніколи не користуватися цим класом. Це насправді також не потрібно (за винятком двійкового форматування числа, оскільки звичайний ToStringметод класів чисел не пропонує відповідного методу для цього).


7

Якщо ви не впевнені на 100% у своїх введеннях, що рідко буває, вам слід використовувати 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.

Швидкість розбору стає другорядною, коли ви видаєте виняток, оскільки там не набагато повільніше, ніж виняток.


4

Тут багато ненависті до класу Convert ... Щоб трохи збалансувати, є одна перевага для Convert - якщо вам вручають об’єкт,

Convert.ToDouble(o);

може просто повернути значення легко, якщо o вже є Double (або int, або що-небудь легко випробовуване).

Використання Double.Parse або Double.TryParse чудово, якщо у вас це вже є в рядку, але

Double.Parse(o.ToString());

має піти зробити рядок , щоб бути розібрана першої і в залежності від вашого входу , які можуть бути більш дорогими.


1
+1: я бачу вашу точку зору, синтаксичний аналіз вкладених чисел / рядків з числом всередині System.Object досить простий, замість масивної перевірки типу. Але в основному я погоджуюсь з іншими відповідями: Convert.ToSomething()це набагато дорожче, ніж Parse / TryParse, особливо в контексті ітерацій
T-moty

Для мене Convert.ToDouble (o) має кілька простих аутів, якщо те, що є в коробці, вже є числом, але справжнім вбивцею Convert є те, що він не має .TryToDouble (o, out d); Враховуючи, наскільки дорогими є винятки (і наскільки ви впевнені - чи ні - вхідних даних), це великі додаткові витрати на Convert.
user1664043

2

Double.TryParse IMO.

Вам простіше впоратися, Ви точно знатимете, де сталася помилка.

Тоді ви можете впоратися з цим, як вважаєте за потрібне, якщо воно повертає false (тобто не вдалося перетворити).


2

Я завжди віддавав перевагу використанню TryParse()методів, оскільки це призведе до успіху або невдалого перетворення, не турбуючись про винятки.


2

Це цікаве старе питання. Я додаю відповідь, оскільки ніхто не помітив декількох речей із початковим запитанням.

Що швидше: Convert.ToDouble або Double.TryParse? Що безпечніше: Convert.ToDouble або Double.TryParse?

Я збираюся відповісти на обидва ці питання (відповідь оновлю пізніше), докладно, але спочатку:

З міркувань безпеки, що кожен програміст пропустив у цьому питанні, це рядок (наголос мій):

Він додає лише дані, що є числами з кількома цифрами (1000 1000,2 1000,34 - кома є роздільником у російських стандартах ).

Далі йде цей приклад коду:

Convert.ToDouble(regionData, CultureInfo.CurrentCulture);

Цікавим тут є те, що якщо електронні таблиці мають російський формат чисел, але Excel неправильно набрав поля комірок, яка правильна інтерпретація значень, що надходять з Excel?

Ось ще одна цікава річ щодо двох прикладів щодо швидкості:

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

Це, швидше за все, буде генерувати MSIL, який виглядає так:

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

У цьому сенсі ми, мабуть, можемо порівняти загальну кількість інструкцій MSIL, виконуваних кожною програмою - про це пізніше, коли я оновлюватиму цю публікацію.

Я вважаю, що код повинен бути правильним, зрозумілим та швидким ... У такому порядку!


1

Особисто я вважаю, що TryParseметод легше читати, і який із них ви насправді хочете використовувати, залежить від вашого випадку використання: якщо помилки можна обробляти локально, ви очікуєте помилок, і бул від TryParseцього хороший, інакше ви можете просто дозволити винятки літають.

Я би також очікував, що TryParseце буде швидшим, оскільки це дозволяє уникнути накладних витрат на обробку винятків. Але для порівняння різних можливостей використовуйте контрольний інструмент, як MiniBench Джона Скіта .


Зворотній зв'язок щодо цієї відповіді: Якщо запитання задають питання про те, що швидше та безпечніше, відповідь не повинна починатися з: "Особисто" і включати здогадки типу: "Я б очікував ...". Це лише особисті думки та коментарі, а не хороша відповідь.
PandaWood
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.