В VB.NET это происходит:
Dim x As System.Nullable(Of Decimal) = Nothing
Dim y As System.Nullable(Of Decimal) = Nothing
y = 5
If x <> y Then
Console.WriteLine("true")
Else
Console.WriteLine("false") '' <-- I got this. Why?
End If
Но в C # такое бывает:
decimal? x = default(decimal?);
decimal? y = default(decimal?);
y = 5;
if (x != y)
{
Debug.WriteLine("true"); // <-- I got this -- I'm with you, C# :)
}
else
{
Debug.WriteLine("false");
}
Почему есть разница?
default(decimal?)
что возвращается 0, а неnull
.null
If
условных выражениях VB не требуется оценивать как логическое ... uuuugh EDIT: Итак,Nothing <> Anything = Nothing
что приводит к выборуIf
маршрута отрицательного / else.Ответы:
VB.NET и C # .NET - это разные языки, созданные разными командами, которые сделали разные предположения об использовании; в этом случае семантика сравнения NULL.
Лично я предпочитаю семантику VB.NET, которая, по сути, дает NULL семантику «Я еще не знаю». Затем сравнение 5 с «Еще не знаю». естественно «я еще не знаю»; т.е. NULL. Это имеет дополнительное преимущество в виде зеркального отображения поведения NULL в (в большинстве, если не во всех) базах данных SQL. Это также более стандартная (чем в C #) интерпретация трехзначной логики, как объясняется здесь .
Команда C # сделала разные предположения о том, что означает NULL, что привело к разнице в поведении, которую вы показываете. Эрик Липперт написал в блоге о значении NULL в C # . Пер Эрик Липперт: «Я также писал о семантике пустых значений в VB / VBScript и JScript здесь и здесь ».
В любой среде, в которой возможны значения NULL, важно признать, что на закон исключенного среднего (т. Е. Что A или ~ A тавтологически истинны) больше нельзя полагаться.
Обновить:
A
bool
(в отличие от abool?
) может принимать только значения TRUE и FALSE. Однако языковая реализация NULL должна решить, как NULL распространяется через выражения. В VB выражения5=null
и5<>null
ОБА возвращают ложь. В C #, из сопоставимых выражений5==null
и5!=null
тольковторойпервый [обновление 2014-03-02 - PG] возвращает ложь. Однако в ЛЮБОЙ среде, поддерживающей значение null, программист должен знать таблицы истинности и распространение нуля, используемые этим языком.Обновить
Статьи в блоге Эрика Липперта (упомянутые в его комментариях ниже) по семантике сейчас находятся по адресу:
30 сентября 2003 г. - A Whole Lot of Nothing
1 октября 2003 г. - Еще немного ни о чем
источник
bool
не может быть трех значений, только два. Этоbool?
может иметь три значения.operator ==
иoperator !=
оба возвращаютсяbool
, нетbool?
, независимо от типа операндов. Кроме того,if
оператор может принимать только abool
, но не abool?
.5=null
и5<>null
недействительны. И5 == null
и5 != null
, вы уверены , что это второе , что возвращаетсяfalse
?Потому что
x <> y
возвращаетNothing
вместоtrue
. Он просто не определен, посколькуx
не определен. (аналогично SQL null).Примечание: VB.NET
Nothing
<> C #null
.Вы также должны сравнивать значение a,
Nullable(Of Decimal)
только если оно имеет значение.Таким образом, VB.NET выше сравнивается примерно с этим (что выглядит менее некорректным):
Спецификация языка VB.NET :
Например:
источник
Посмотрите на сгенерированный CIL (я преобразовал оба на C #):
C #:
Visual Basic:
Вы увидите, что сравнение в Visual Basic возвращает значение Nullable <bool> (не bool, false или true!). А undefined, преобразованный в bool, является ложным.
Nothing
по сравнению с тем, что всегдаNothing
, а не ложью в Visual Basic (это то же самое, что и в SQL).источник
Проблема, которая здесь наблюдается, является частным случаем более общей проблемы, заключающейся в том, что количество различных определений равенства, которые могут быть полезны, по крайней мере, в некоторых обстоятельствах, превышает количество общедоступных средств их выражения. Эта проблема в некоторых случаях усугубляется неудачным убеждением в том, что использование разных средств проверки равенства приводит к разным результатам, сбивает с толку, и такой путаницы можно избежать, если различные формы равенства дают одинаковые результаты, когда это возможно.
На самом деле фундаментальной причиной путаницы является ошибочное убеждение, что следует ожидать, что разные формы проверки на равенство и неравенство дадут один и тот же результат, несмотря на тот факт, что разная семантика полезна в разных обстоятельствах. Например, с точки зрения арифметики полезно иметь возможность
Decimal
сравнивать те , которые отличаются только количеством конечных нулей, как равные. То же самое дляdouble
таких значений, как положительный ноль и отрицательный ноль. С другой стороны, с точки зрения кэширования или интернирования такая семантика может быть смертельной. Допустим, например, у одного естьDictionary<Decimal, String>
такой, на которыйmyDict[someDecimal]
должно равнятьсяsomeDecimal.ToString()
. Такой объект казался бы разумным, если бы у него было многоDecimal
значения, которые нужно было преобразовать в строку и ожидалось, что будет много дубликатов. К сожалению, если использовать такое кэширование для преобразования 12,3 м и 12,40 м, а затем 12,30 м и 12,4 м, последние значения дадут «12,3» и «12,40» вместо «12,30» и «12,4».Возвращаясь к рассматриваемому вопросу, существует более одного разумного способа сравнения обнуляемых объектов на предмет равенства. C # придерживается точки зрения, что его
==
оператор должен отражать поведениеEquals
. VB.NET придерживается точки зрения, что его поведение должно отражать поведение некоторых других языков, поскольку любой, кто хочет,Equals
может использовать егоEquals
. В некотором смысле правильным решением было бы иметь трехстороннюю конструкцию «if» и требовать, чтобы, если условное выражение возвращает трехзначный результат, код должен указывать, что должно происходить вnull
случае. Поскольку это не вариант с языками как они есть, следующая лучшая альтернатива - просто изучить, как работают разные языки, и признать, что они не совпадают.Между прочим, оператор «Is» в Visual Basic, которого нет в C, можно использовать для проверки того, действительно ли объект, допускающий значение NULL, равен NULL. Хотя можно резонно задаться вопросом,
if
должен ли тест принимать aBoolean?
, наличие обычных операторов сравнения, возвращаемыхBoolean?
вместо того, чтобыBoolean
вызывать их для типов, допускающих значение NULL, является полезной функцией. Между прочим, в VB.NET, если кто-то попытается использовать оператор равенства, а неIs
, вы получите предупреждение о том, что результат сравнения всегда будетNothing
, и его следует использовать,Is
если кто-то хочет проверить, является ли что-то нулевым.источник
== null
. И проверка того, имеет ли тип значения, допускающий значение NULL, значение выполняется с помощью.hasValue
. Какая польза отIs Nothing
оператора? В C # есть,is
но он проверяет совместимость типов. В свете этого я действительно не уверен, что пытается сказать ваш последний абзац.null
, хотя оба языка рассматривают это как синтаксический сахар дляHasValue
проверки, по крайней мере, в тех случаях, когда тип известен (я не уверен какой код генерируется для дженериков).Может быть этот пост вам поможет:
Если я правильно помню, «Ничего» в VB означает «значение по умолчанию». Для типа значения это значение по умолчанию, для ссылочного типа это будет null. Таким образом, ничего не присваивать структуре - это вообще не проблема.
источник
<>
операторе в VB и в том, как он работает с типами, допускающими значение NULL.Это определенная странность VB.
В VB, если вы хотите сравнить два типа, допускающие значение NULL, вы должны использовать
Nullable.Equals()
.В вашем примере это должно быть:
источник
Nullable<>.Equals()
. Можно было ожидать, что он будет работать таким же образом (что и делает C #).Nullable
не существовало в первых версиях .NET, оно было создано после того, как C # и VB.NET в течение некоторого времени отсутствовали и уже определили их поведение нулевого распространения. Вы искренне ожидаете, что язык будет соответствовать типу, который не создавался в течение нескольких лет? С точки зрения программиста на VB.NET, это значение Nullable.Equals, которое не соответствует языку, а не наоборот. (Учитывая, что C # и VB используют одно и то жеNullable
определение, у него не было возможности согласовать его с обоими языками.)Ваш код VB просто неверен - если вы измените «x <> y» на «x = y», в результате вы все равно получите «false». Наиболее распространенный способ выражения this для экземпляров, допускающих значение NULL, - «Not x.Equals (y)», и это приведет к тому же поведению, что и «x! = Y» в C #.
источник
x
нетnothing
, в этом случаеx.Equals(y)
будет сгенерировано исключение.