Double.TryParse или Convert.ToDouble - что быстрее и безопаснее?

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

Ответ 1

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

Ответ 2

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

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

Ответ 3

Рекомендации по разработке .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.

Ответ 4

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

Ответ 5

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

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

Ответ 6

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

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

Convert.ToDouble(o);

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

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

Double.Parse(o.ToString());

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

Ответ 8

Double.TryParse IMO.

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

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

Ответ 9

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

Ответ 10

Лично я считаю, что метод TryParse легче читать, какой из них вы действительно хотите использовать, зависит от вашего прецедента: если ошибки можно обрабатывать локально, вы ожидаете ошибок, а bool из TryParse - хорошо, иначе вы можете просто позволить исключениям летать.

Я бы ожидал, что TryParse будет быстрее, поскольку он избегает накладных расходов на обработку исключений. Но используйте инструмент сравнения, например Jon Skeet MiniBench, чтобы сравнить различные возможности.

Ответ 11

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

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

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