Преобразование переменной double с нулевым значением в строку в VB.NET

#string #vb.net #double #nullable

#строка #vb.net #двойной #обнуляемый

Вопрос:

Недавно я столкнулся со странным поведением обнуляемого двойника. Поскольку мне нужно превратить обнуляемую переменную в строку с точно установленными цифрами, я использую метод .ToString(format) . Когда я применяю этот метод к вышеупомянутой переменной с нулевым значением, вместо того, чтобы получать преобразованное число, как мне нужно, я получаю только первую цифру этого числа (пример приведен ниже). Конечно, я могу преобразовать значение null в double, и это решит проблему, но почему это происходит? Большое вам спасибо за ваш вклад.

Пример:

 'Nullable Double
Dim value As Double? = 867
Dim convertedValue As String = value.ToString("0.00000")
Console.WriteLine(convertedValue)
'Output: 8

'Not nullable Double
Dim value As Double = 867
Dim convertedValue As String = value.ToString("0.00000")
Console.WriteLine(convertedValue)
'Output: 867.00000
 

Комментарии:

1. Этот код даже не будет компилироваться Option Strict On , что должно быть почти ВСЕГДА. Вы должны включить это On в свойствах проекта, а также в настройках IDE, чтобы оно было On по умолчанию для будущих проектов.

Ответ №1:

Метод, который вы пытаетесь вызвать, не существует. A Double? на самом деле является a Nullable(Of Double) . Любой метод, который вы вызываете, должен быть членом Nullable(Of T) структуры. Как этот тип может иметь ToString перегрузку, которая принимает строку числового формата в качестве аргумента, когда T это может быть нечисловой тип? Вот документация по этому Nullable(Of T).ToString методу:

https://docs.microsoft.com/en-au/dotnet/api/system.nullable-1.tostring?view=net-5.0

Как вы можете видеть, такой перегрузки нет, в отличие от Double типа:

https://docs.microsoft.com/en-au/dotnet/api/system.double.tostring?view=net-5.0

Если вы хотите использовать строку числового формата, то вам нужно число, а a Double? — это не число. Вот метод, который вы можете использовать, который будет форматировать значение как число, если оно равно единице, и обычно в противном случае:

 Private Function FormatNullableDouble(number As Double?, format As String) As String
    Return If(number.HasValue,
              number.Value.ToString(format),
              number.ToString())
End Function
 

Вы могли бы назвать это примерно так:

 Dim convertedValue As String = FormatNullableDouble(value, "0.00000")
 

EDIIT:

Чтобы было ясно, поскольку у вас есть Option Strict Off , компилятор игнорирует, что ваш код не имеет смысла, и предполагает, что он будет иметь смысл во время выполнения. Когда наступает время выполнения, система изо всех сил старается найти способ заставить его работать. Что на самом деле получается, так это то, что это:

 value.ToString("0.00000")
 

на самом деле означает это:

 value.ToString().Chars(CInt("0.00000"))
 

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

 value.ToString
 

эквивалентно этому:

 value.ToString()
 

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

Теперь ему просто нужно что-то сделать со строкой формата в круглых скобках. Предыдущий ToString вызов возвращает a String , и вы можете проиндексировать a String , чтобы получить Char значение по этому индексу, поэтому предполагается, что это то, что вы пытаетесь сделать. Он преобразует вашу строку формата в an Integer , а затем получает Char из String этого индекса. Вот почему значение 867 выдает 8 в качестве выходного значения. Вы преобразуете число 867 в a String , затем преобразуете String "0.00000" в an Integer , чтобы получить 0, затем получаете the Char с индексом 0 из String "867" , который равен "8"c .

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

Комментарии:

1. Я уже создал метод расширения. Мне было только интересно, почему это происходит. Большое вам спасибо за ваш ответ. Теперь все ясно.

2. @PepaZdepa, я добавил подробное объяснение того, что именно происходит и почему.

3. Большое вам спасибо. Это очень ценится!