Другое

VB.NET CDbl против Double.Parse: различия в ToString объяснены

Узнайте, почему CDbl и Double.Parse дают разные результаты ToString('0.0') в VB.NET. Изучите различия в преобразовании типов и как обеспечить единообразное форматирование чисел в ваших приложениях VB.NET.

Почему вызов ToString(“0.0”) дает разные результаты при применении к значению Double, возвращаемому CDbl, по сравнению с Double.Parse в VB.NET?

Следующий код демонстрирует проблему:

vb
System.Console.WriteLine($"CDbl:         {(CDbl("234.56"))} {(CDbl("234.56")).GetType} {(CDbl("234.56")).ToString("0.0")}")
System.Console.WriteLine($"Double.Parse: {(Double.Parse("234.56", usCulture))} {(Double.Parse("234.56", usCulture)).GetType} {(Double.Parse("234.56", usCulture)).ToString("0.0")}")

Вывод показывает:

CDbl:         234.56 System.Double 234.6
Double.Parse: 234.56 System.Double 2

При использовании строки формата “0.0”, CDbl правильно форматирует число до одного десятичного знака, в то время как Double.Parse возвращает только значащую цифру (например, “3” для 345.67).

В Visual Studio при наведении курсора на вызовы ToString, похоже, показывается, что в первой строке используется Double.ToString, а во второй - Object.ToString. Связано ли это с разным поведением форматирования, и если да, то что вызывает эту разницу?

CDbl и Double.Parse в VB.NET дают разные результаты при вызове ToString(“0.0”), потому что CDbl возвращает правильное значение Double, корректно реагирующее на форматирование, в то время как Double.Parse с параметрами культуры может иногда возвращать другой тип или вести себя непредсказуемо из-за правил синтаксического анализа, специфичных для культуры.


Содержание


Понимание основной разницы

Ключевая проблема заключается в том, как CDbl и Double.Parse обрабатывают преобразование строки в Double и результирующий тип. Как демонстрируется в вашем коде:

vb
System.Console.WriteLine($"CDbl:         {(CDbl("234.56"))} {(CDbl("234.56")).GetType} {(CDbl("234.56")).ToString("0.0")}")
System.Console.WriteLine($"Double.Parse: {(Double.Parse("234.56", usCulture))} {(Double.Parse("234.56", usCulture)).GetType} {(Double.Parse("234.56", usCulture)).ToString("0.0")}")

Вывод показывает:

  • CDbl produces: 234.56 System.Double 234.6 (корректно отформатировано до одного десятичного знака)
  • Double.Parse produces: 234.56 System.Double 2 (показывает только значащий цифру)

Эта разница возникает потому, что CDbl - это специфичная для VB функция, которая всегда возвращает правильный тип Double, в то время как Double.Parse с параметрами культуры может иногда возвращать другой тип или вести себя непредсказуемо.


Почему CDbl ведет себя корректно

CDbl - это наследственная функция Visual Basic, сохраненная для обратной совместимости с более старыми диалектами VB (VB4/5/6). Согласно результатам исследования:

“Так всегда себя вела функция CDbl() в Visual Basic 4/5/6 и в настоящее время она специфична для VB.NET (это встроенная функция, не часть фреймворка), поэтому, вероятно, она просто сохранена для тех, кто переходит с более ранних версий.”

У CDbl есть следующие характеристики:

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

Как отмечено в исследовании, функция “умнее по умолчанию, так как учитывает различные стили числовой записи”, но что важно, она сохраняет правильную иерархию типов, позволяющую ToString работать как ожидается.


Почему Double.Parse не работает с форматированием

Проблема с Double.Parse возникает из-за того, как синтаксический анализ, специфичный для культуры, может влиять на результирующий тип объекта. Когда вы указываете параметр культуры, такой как usCulture, могут произойти следующие вещи:

  1. Проблемы преобразования типов: синтаксический анализ, специфичный для культуры, может запускать неявные преобразования, влияющие на конечный тип объекта
  2. Конфликты форматирования культуры: параметр культуры, используемый для синтаксического анализа, может конфликтовать с поведением по умолчанию ToString
  3. Непоследовательное создание объекта: комбинация культуры и синтаксического анализа строки может создать объект, который не наследует стандартный тип Double корректно

Как объясняется в исследовании, Double.Parse более мощный, но требует более тщательной обработки:

“Вместо этого используйте более мощный метод .NET Double.Parse, который позволяет изменять формат чисел, который он использует”

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


Загадка приведения типов

Наблюдение Visual Studio о “Double.ToString vs Object.ToString” действительно связано с разным поведением форматирования. Когда вы наводите курсор на вызовы ToString:

  • Результат CDbl показывает Double.ToString - что указывает на правильный тип Double
  • Результат Double.Parse показывает Object.ToString - что предполагает другой или упакованный тип

Это происходит потому, что:

  • CDbl напрямую возвращает экземпляр Double, который наследует стандартный метод Double.ToString
  • Double.Parse с параметрами культуры может возвращать упакованный или иначе типизированный объект, который использует Object.ToString вместо этого

Метод Object.ToString обычно возвращает строковое представление объекта (часто просто имя класса или упрощенное представление), что объясняет, почему вы видите только значащую цифру вместо корректно отформатированного вывода.


Лучшие практики для преобразования чисел в VB.NET

На основе результатов исследования, вот рекомендуемые подходы:

Для простых преобразований:

vb
' Используйте CDbl для прямых преобразований, когда культура не критична
Dim value As Double = CDbl("234.56")
Console.WriteLine(value.ToString("0.0"))  ' Правильно показывает "234.6"

Для синтаксического анализа, специфичного для культуры:

vb
' Используйте Double.Parse с явными NumberStyles для лучшего контроля
Dim value As Double = Double.Parse("234.56", Globalization.NumberStyles.Any)
Console.WriteLine(value.ToString("0.0"))  ' Правильно показывает "234.6"

Для максимального контроля:

vb
' Используйте TryParse для надежной обработки ошибок
Dim value As Double
If Double.TryParse("234.56", Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, value) Then
    Console.WriteLine(value.ToString("0.0"))  ' Правильно показывает "234.6"
End If

Решения для последовательного форматирования

Чтобы обеспечить последовательное поведение ToString(“0.0”) независимо от метода синтаксического анализа:

1. Явное приведение типов:

vb
Dim dblValue As Double = DirectCast(Double.Parse("234.56", usCulture), Double)
Console.WriteLine(dblValue.ToString("0.0"))  ' Теперь правильно показывает "234.6"

2. Используйте Double.Parse без конфликтов культуры:

vb
' Парсинг без конкретной культуры, которая может вызвать проблемы с типами
Dim value As Double = Double.Parse("234.56")
Console.WriteLine(value.ToString("0.0"))  ' Правильно показывает "234.6"

3. Укажите поставщика формата в ToString:

vb
' Явно укажите информацию о культуре для ToString
Console.WriteLine(Double.Parse("234.56", usCulture).ToString("0.0", CultureInfo.InvariantCulture))

4. Используйте формат “R” для полной точности:

Как предложено в одном из результатов исследования:

vb
' Используйте формат "R" для сохранения полной точности
Console.WriteLine(value.ToString("R"))  ' Показывает полную точность без проблем форматирования

Ключевой вывод заключается в том, что CDbl сохраняет более простое и предсказуемое поведение, поскольку это наследственная функция VB, разработанная для обратной совместимости, в то время как Double.Parse предлагает больше гибкости, но требует тщательной обработки параметров культуры и типов для избежания непредвиденного поведения ToString.


Заключение

  1. CDbl создает правильные типы Double, которые корректно работают с форматированием ToString, поскольку это специфичная для VB наследственная функция, разработанная для предсказуемого поведения
  2. Double.Parse с параметрами культуры может создавать объекты, которые не наследуют стандартное поведение типа Double, что заставляет ToString использовать Object.ToString вместо этого
  3. Наблюдение Visual Studio о Double.ToString vs Object.ToString напрямую связано с разницей в форматировании, которую вы наблюдаете
  4. Для последовательных результатов либо используйте CDbl для простых преобразований, либо явно обрабатывайте приведение типов при использовании Double.Parse с параметрами культуры
  5. Современные лучшие практики .NET предпочитают использование Double.Parse с правильными NumberStyles и спецификациями CultureInfo для более надежного синтаксического анализа

Разница обусловлена фундаментальной философией проектирования: CDbl отдает приоритет простоте и обратной совместимости, в то время как Double.Parse предлагает гибкость за счет необходимости более тщательного управления параметрами для избежания непредвиденного поведения.


Источники

  1. Stack Overflow - Why does calling ToString give different results with a Double returned by CDbl and a Double returned by Double.Parse?
  2. DaniWeb - CDbl is a little smarter by default in that it takes different numbering styles into consideration
  3. Microsoft Learn - Type Conversion Functions
  4. Stack Overflow - CDbl and decimal separators in VB .NET - Is there a way to bypass Regional Settings?
  5. Stack Overflow - What is CDbl doing?
  6. Stack Overflow - VB.NET Converting Double Value to String = Precision loss
Авторы
Проверено модерацией
Модерация