2009-02-25 4 views
74

Мое приложение считывает файл Excel с использованием VSTO и добавляет прочитанные данные в StringDictionary. Он добавляет только данные, которые представляют собой цифры с несколькими цифрами (1000 1000,2 1000,34 - запятая - это разделитель в российских стандартах).Double.TryParse или Convert.ToDouble - что быстрее и безопаснее?

Что лучше проверить, соответствует ли текущая строка подходящему номеру?

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

+0

FYI, double.TryParse - это то же самое, что и try {result = double.Parse (s); return true; } catch {return false; }. Преобразование по существу является оберткой для обеих групп с перегрузкой. Неважно, как вы это делаете. Но, как указал Джон, подумайте о том, как обращаться с плохим вводом. –

+10

Двухместный.TryParse - это не то же самое, что double.Parse, завернутый в try..catch. Семантика одна и та же, но путь кода отличается. TryParse сначала проверяет, что строка является числом, используя внутренний Number.TryStringToNumber, тогда как Parse предполагает, что это уже число/double. –

ответ

125

Я сделал быстрый ненаучный тест в режиме деблокирования. Я использовал два входа: «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()); // сбой double dblParse = Double.Parse ((- 1/30000) .ToString()); // отлично работает –

7

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

2

Double.TryParse IMO.

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

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

7

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

7

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

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

2

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

43

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

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

+5

Джон, Можете ли вы рассказать о том, почему вы предпочитаете double.Parse over Convert.ToDouble? –

+10

@dnorthut: Я редко хочу, чтобы null был преобразован в 0 (что Convert.ToDouble делает), в основном. Это также, как правило, более гибкое. Я просто склоняюсь к конкретным методам ... –

1

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

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

+0

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

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. 

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

3

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

Convert.ToDouble(o); 

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

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

Double.Parse(o.ToString()); 

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

+0

+1: я вижу вашу точку зрения, разбор боксированных чисел/строк с номером внутри объекта System.Object довольно просто, вместо этого массивная проверка типа. Но в основном я согласен с другими ответами: 'Convert.ToSomething()' так дорого, а не Parse/TryParse, особенно в контексте итерации –

+0

Для меня Convert.ToDouble (o) имеет несколько простых аутов, если что в коробке уже является числом, но реальным убийцей для Convert является то, что он не имеет .TryToDouble (o, out d); Учитывая, насколько дорогими исключениями (и насколько вы уверены, или нет) входов), это большой дополнительный расход Convert. – user1664043

Смежные вопросы