Почему существует разница в проверке 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");
}


почему есть разница?

928   7  

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 Nothing C# 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

    Ничего не найдено.