Почему существует разница в проверке null против значения в VB.NET а C#?
In 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");
}
почему есть разница?
7 ответов:
VB.NET и C#.NET это разные языки, построенные разными командами, которые сделали разные предположения об использовании; в этом случае семантика нулевого сравнения.
мои личные предпочтения для VB.NET семантика, которая по сути дает NULL семантику "я еще не знаю". Затем сравнение 5 с "я еще не знаю". естественно, "я еще не знаю"; т. е. NULL. Это имеет дополнительное преимущество зеркального отображения поведения NULL в (большинство, если не все) SQL база данных. Это также более стандартная (чем C#) интерпретация трехзначной логики, как объяснено здесь.
команда C# сделала разные предположения о том, что означает NULL, в результате чего вы показываете разницу в поведении. Эрик Липперт написал блог о значении NULL в C#. Пер Эрик Липперт: "я также писал о семантике нулей в VB / VBScript и JScript здесь и здесь".
в любом среда, в которой возможны нулевые значения, имплантирует признание того, что закон исключенной середины (т. е. что A или ~a тавтологически истинно) больше не может полагаться.
обновление:
A
bool(вместоbool?) может принимать только значения TRUE и FALSE. Однако языковая реализация NULL должна решить, как NULL распространяется через выражения. В VB выражения5=nullи5<>nullоба возвращают false. В C# из сопоставимые выражения5==nullи5!=nullтольковторойпервый [обновлено 2014-03-02-PG] возвращает false. Однако в любой среде, которая поддерживает null, программист должен знать таблицы истинности и null-распространение, используемые этим языком.
, потому что
x <> yвозвращаетNothingвместоtrue. Он просто не определен, так какxне определен. (аналогично SQL null).Примечание: VB.NET
NothingC#null.вы также должны сравнить значение
Nullable(Of Decimal)только если он имеет значение.так что VB.NET выше сравнивается аналогично этому(что выглядит менее неверно):
If x.HasValue AndAlso y.HasValue AndAlso x <> y Then Console.WriteLine("true") Else Console.WriteLine("false") End Ifв VB.NET спецификация языка:
7.1.1 Типы Значений Nullable ... Тип nullable value может содержать те же значения, что и тип nullable версии типа, а также значение null. Таким образом, для нулевых тип значения, ничего не присваивая переменной типа устанавливает значение переменной значение null, а не ноль значение тип.
например:
Dim x As Integer = Nothing Dim y As Integer? = Nothing Console.WriteLine(x) ' Prints zero ' Console.WriteLine(y) ' Prints nothing (because the value of y is the null value) '
посмотрите на сгенерированный CIL (я преобразовал оба в C#):
C#:
private static void Main(string[] args) { decimal? x = null; decimal? y = null; y = 5M; decimal? CS00 = x; decimal? CS01 = y; if ((CS00.GetValueOrDefault() != CS01.GetValueOrDefault()) || (CS00.HasValue != CS01.HasValue)) { Console.WriteLine("true"); } else { Console.WriteLine("false"); } }Visual Basic:
[STAThread] public static void Main() { decimal? x = null; decimal? y = null; y = 5M; bool? VB$LW$t_struct$S3 = new bool?(decimal.Compare(x.GetValueOrDefault(), y.GetValueOrDefault()) != 0); bool? VB$LW$t_struct$S1 = (x.HasValue & y.HasValue) ? VB$LW$t_struct$S3 : null; if (VB$LW$t_struct$S1.GetValueOrDefault()) { Console.WriteLine("true"); } else { Console.WriteLine("false"); } }вы увидите, что сравнение в Visual Basic возвращает Nullable
(не bool, false или true!). И undefined, преобразованный в bool, является ложным.
Nothingпо сравнению с тем, что всегдаNothing, не false в Visual Basic (это то же самое, что и в SQL).
Decimal, которые отличаются только количеством незначащих нулей равны. Также для
doubleзначения, как положительный ноль и отрицательный ноль. С другой стороны, с точки зрения кэширования или интернирования такая семантика может быть смертельной. Предположим, например, что у одного былоDictionary<Decimal, String>такое, чтоmyDict[someDecimal]должна быть равнаsomeDecimal.ToString(). Такой объект казался бы разумным, если бы у него было многоDecimalзначения, которые один хотел преобразовать в строку и ожидал, что будет много дубликатов. К сожалению, если использовать такое кэширование для преобразования 12.3 m и 12.40 m, а затем 12.30 m и 12.4 m, последние значения будут выход "12.3", и "12.40" вместо "12.30"и " 12.4".возвращаясь к рассматриваемому вопросу, существует более чем один разумный способ сравнения обнуляемых объектов для равенства. C# принимает точку зрения, что его
==оператор должен отражать поведениеEquals. VB.NET считает, что его поведение должно отражать поведение некоторых других языков, так как любой, кто хочетEqualsповедение могли бы использоватьEquals. В некотором смысле, правильным решением было бы имейте трехстороннюю конструкцию " if " и требуйте, чтобы если условное выражение возвращает трехзначный результат, код должен указать, что должно произойти вnullслучае. Поскольку это не вариант с языками, как они есть, следующая лучшая альтернатива-просто узнать, как работают разные языки и признать, что они не одинаковы.кстати, оператор "Is" Visual Basic, который отсутствует в C, может быть использован для проверки того, является ли объект null, фактически, null. В то время как можно было бы разумно спросить, является ли
ifтест должен принятьBoolean?, имея нормальные операторы сравнения возвращаютBoolean?, а неBooleanпри вызове на типы, допускающие значение NULL-это полезная функция. Кстати, в VB.NET, если кто-то пытается использовать оператор равенства, а неIs, вы получите предупреждение, что результат сравнения всегда будетNothingи нужно использоватьIsесли кто-то хочет проверить, если что-то является нулем.
может быть этой сообщение хорошо поможет вам:
Если я правильно помню, 'Nothing' в VB означает "значение по умолчанию". Для типа значения это значение по умолчанию, для ссылочного типа-значение null. Таким образом, присвоение ничего структуре, не является проблемой вообще.
это определенная странность VB.
в VB, если вы хотите сравнить два типа nullable, вы должны использовать
Nullable.Equals().в вашем примере это должно быть:
Dim x As System.Nullable(Of Decimal) = Nothing Dim y As System.Nullable(Of Decimal) = Nothing y = 5 If Not Nullable.Equals(x, y) Then Console.WriteLine("true") Else Console.WriteLine("false") End If
ваш код VB просто неверен - если вы измените "x y "на" x = y", у вас все равно будет" false " в результате. Наиболее распространенным способом выражения этого для nullable экземпляров является "Not x. Equals(y)", и это приведет к тому же поведению, что и " x != y " в C#.
Comments