Double.TryParse или Convert.ToDouble - что быстрее и безопаснее? - PullRequest
78 голосов
/ 25 февраля 2009

Мое приложение читает файл 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)?

Ответы [ 11 ]

128 голосов
/ 25 февраля 2009

Я провел быстрый ненаучный тест в режиме выпуска. Я использовал два входа: «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 с некоторыми цифрами в поддержку.

46 голосов
/ 25 февраля 2009

Для начала я бы использовал double.Parse вместо Convert.ToDouble.

Относительно того, следует ли вам использовать Parse или TryParse: можете ли вы продолжить, если есть плохие входные данные, или это действительно исключительное условие? Если это исключение, используйте Parse и дайте ему взорваться, если ввод плохой. Если это ожидается и может быть аккуратно обработано, используйте TryParse.

8 голосов
/ 25 февраля 2009

В руководствах по разработке .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 голосов
/ 19 декабря 2011

Если вы не на 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.

Скорость разбора становится вторичной, когда вы генерируете исключение, потому что оно не намного медленнее исключения.

7 голосов
/ 25 февраля 2009

Обычно я стараюсь избегать класса Convert (что означает: я им не пользуюсь), потому что нахожу его очень запутанным: код дает слишком мало подсказок о том, что именно здесь происходит, поскольку Convert допускает много семантически очень разные преобразования происходят с одним и тем же кодом. Это мешает программисту контролировать, что именно происходит.

Поэтому я никогда не советую использовать этот класс. Это также не является необходимым (за исключением двоичного форматирования числа, потому что обычный ToString метод числовых классов не предлагает подходящий метод для этого).

7 голосов
/ 25 февраля 2009

Если вы не собираетесь обрабатывать исключение, используйте TryParse. TryParse работает быстрее, потому что ему не нужно работать со всей трассировкой стека исключений.

3 голосов
/ 14 сентября 2015

Много ненависти к классу Convert здесь ... Просто чтобы немного подвести итог, есть одно преимущество для Convert - если вам вручают объект,

Convert.ToDouble(o);

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

Использование Double.Parse или Double.TryParse прекрасно, если у вас уже есть это в строке, но

Double.Parse(o.ToString());

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

2 голосов
/ 25 февраля 2009

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

2 голосов
/ 25 февраля 2009

Double.TryParse IMO.

Вам легче справиться, вы точно будете знать, где произошла ошибка.

Тогда вы можете справиться с ним так, как считаете нужным, если он вернет false (т.е. не смог преобразовать).

1 голос
/ 04 декабря 2018

Это интересный старый вопрос. Я добавляю ответ, потому что никто не заметил пару вещей с оригинальным вопросом.

Что быстрее: 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, выполняемых каждой программой - подробнее об этом позже, когда я обновлю этот пост.

Я считаю, что код должен быть правильным, ясным и быстрым ... В таком порядке!

...