Присвоение значения DateTime, допускающего значение NULL, с помощью встроенного IfElse устанавливает переменную в 01.01.0001 12:00:00

В VB.NET следующий код:

Dim myBool As Boolean = False
Dim myDate As Date? = If(myBool, Date.Today, Nothing)
Console.WriteLine(myDate)

Производит: 1/1/0001 12:00:00 AM

Однако, если я напишу это как:

Dim myBool As Boolean = False
Dim myDate As Date?

If myBool Then
    myDate = Date.Today
Else
    myDate = Nothing
End If
Console.WriteLine(myDate)

Затем он, как и ожидалось, выведет значение null/nothing.

Что здесь происходит, и как я могу использовать однострочный код для назначения даты или значения null для DateTime с нулевым значением в VB.NET без того, чтобы по умолчанию он фактически не был установлен на 01/01/0001 12:00:00 AM?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
72
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Выражение If(myBool, Date.Today, Nothing) должно стоять само по себе и оцениваться без какого-либо влияния со стороны левой части задания; он не знает, что ему будет назначено значение DateTime, допускающее значение NULL.

Это неудачно для VB.Net, но при рассмотрении типов Nullable мы должны помнить, что они были созданы с учетом концепции null в C#, которая отличается от Nothing в VB.Net. В частности, Nothing на самом деле ближе к выражению default(T) в C# (или теперь просто default).

Поэтому часто бывает полезно рассмотреть адаптацию кода C#. В этом случае фактический прямой перевод исходной строки кода на C# выглядит так, где null никогда не используется:

DateTime? myDate = myBool ? DateTime.Today : default;

Вы обнаружите, что это соответствует поведению VB.Net, которое вы уже наблюдали. Итак, мы видим, что окончательным результатом выражения является стандартное (не допускающее значение NULL) значение DateTime, где Nothing интерпретируется как значение по умолчанию для этого типа (DateTime.MinValue)... которое выглядит как 1/1/0001 12:00:00 AM при записи на консоль в вашей системе.


Стоит отметить, что выражение Nothing также должно стоять отдельно в версии кода If/Else, опять же без учета левой части присваивания.

myDate = Nothing

На этот раз все работает так, как ожидалось, потому что теперь default в переводе C# рассматривается как ссылка, а не значение, поэтому результатом является истинное null вместо ненулевого значения по умолчанию для типа значения.

Но кроме того, этот блок Elseне нужен, и если его полностью опустить, вы получите тот же результат.


Вместо этого, чтобы добиться желаемого результата, вы можете сделать следующее:

If(myBool, Date.Today, CType(Nothing, DateTime?))

Или это:

If(myBool, Date.Today, New Nullable(Of DateTime))

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

Dim myBool As Boolean = False
Dim myDate As Date?
If myBool Then myDate = Date.Today
Console.WriteLine(myDate)

Еще один шаг к полному пониманию всего этого — это If(), поскольку условное выражение If(myBool, Date.Today, Nothing) не является вызовом функции. У него есть некоторая функциональная семантика, но If() здесь на самом деле является оператором .

Это позволяет компилятору применить к нему специальную обработку, поэтому Nothing, используемый в качестве второго аргумента, может быть оценен с учетом типа выражения Date.Today. В противном случае каждый аргумент функции должен был бы полностью разрешаться независимо — без учета других — перед входом в функцию, и Nothing всё равно была бы нетипизированной (или Object) null ссылкой.

Спасибо за такое подробное объяснение. Nothing на самом деле быть default так неинтуитивно! Проклятие VB.NET...

WSC 05.04.2024 00:22

Я верю, что это сработает.

    Dim myBool As Boolean = False
    Dim myDate As Date? = If(myBool, Date.Today, New Date?)
    Debug.WriteLine(myDate)

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

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

Date? — это сокращение от Nullable(of DateTime).

Когда вы пишете:

Dim myDate As Date? = If(myBool, Date.Today, Nothing)

Если вы считаете, что Nothing означает значение null, компилятор должен определить тип, возвращаемый ключевым словом If(...), на основе предоставленных аргументов. Date.Today, очевидно, является типом DateTime, а Nothing можно интерпретировать как значение по умолчанию для типа DateTime, поэтому он выбирает DateTime в качестве возвращаемого типа, поскольку его можно неявно преобразовать в Nullable(of DateTime).

Если вы попытаетесь написать эквивалент C# как:

DateTime? myDate = myBool ? DateTime.Today : null;

Компилятор C# пометит его с ошибкой «Тип условного выражения не может быть определен, поскольку нет неявного преобразования между DateTime и <null>». Имея это в виду, можно сказать, что это «ошибка» в компиляторе VB, которую следует устранить.

Как указывают другие ответы, решение состоит в том, чтобы код был однозначным в отношении того, что должно быть возвращено предложением If(...), и заменить Nothing значением Nullable(Of DateTime)`, например:

Dim myDate As Date? = If(myBool, Date.Today, New Date?())

Кстати, эквивалент C# использует default вместо null, например DateTime? myDate = myBool ? DateTime.Today : default;, что мы видим, потому что он также дублирует наблюдаемое поведение VB.Net.

Joel Coehoorn 04.04.2024 22:00

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