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)?

Ответов (11)

Решение

Я провел быстрый ненаучный тест в режиме Release. Я использовал два входа: «2.34523» и «badinput» в обоих методах и повторил 1000000 раз.

Действительный ввод:

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

Как и ожидалось, не сильно отличается. Для всех намерений и целей, для действительного ввода, это одно и то же.

Некорректный ввод:

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

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

Итак, вот еще одно голосование за TryParse с некоторыми цифрами в поддержку.

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

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

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

Convert.ToDouble(o);

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

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

Double.Parse(o.ToString());

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

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

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

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

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

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

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

В рекомендациях по проектированию .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 напрямую.

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

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

Double.TryParse IMO.

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

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

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

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

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