Удваивать.Попробуйте проанализировать или преобразовать.В Double - что быстрее и безопаснее?

StackOverflow https://stackoverflow.com/questions/586436

  •  06-09-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

Другие советы

Для начала я бы использовал double.Parse вместо того , чтобы Convert.ToDouble в первую очередь.

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

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

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

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

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

Если вы не уверены на 100% в своих входных данных, что случается редко, вам следует использовать Double.Попробуйте проанализировать.

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.Синтаксический анализ или Double.TryParse отлично подходит, если у вас уже есть это в строке, но

Double.Parse(o.ToString());

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

Дважды.Попробуйте проанализировать IMO.

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top