"ulong == ulong?"оценивается как "ulong == ulong" работает правильно - PullRequest
4 голосов
/ 15 октября 2019

Если мы используем оператор == между выражением ulong и выражением ulong?, то перегрузка оператора bool ulong(ulong left, ulong right) будет использоваться.

Showing use of == operator

Другими словами, оператор считает оба выражения ненулевыми.

В этом примере программы equal правильно становится ложным, без исключений.

void Main()
{
    var temp = new Temp(0);
    object temp2 = null;

    var equal = temp.Id == (temp2 as Temp)?.Id; // False :) but how?
}

public class Temp
{
    public ulong Id {get;}

    public Temp(ulong id)
    {
        this.Id = id;
    }
}
  1. Как это не бросить? Нет преобразования ulong? со значением null в ulong. (ulong)(ulong?)null throws: «Обнуляемый объект должен иметь значение.»
  2. Возвращает ли это правильное значение для каждого возможного значения из ulong?, включая ноль? Если так, то как? Тип ulong? имеет еще одно возможное значение, чем ulong, поэтому должен быть один набор из двух значений, которые сопоставляются с одинаковым ulong значением, что приведет к одному ложному положительному «истинному» результату.

Теоретически я мог бы представить, что null объединяется с default(ulong), но тогда результат в моем примере выше будет верным, что будет неверным ответом. И, как мы видим, компилятор не делает эту ошибку - он отвечает правильно.

Ответы [ 2 ]

9 голосов
/ 15 октября 2019

С MSDN :

Поднятые операторы разрешают предопределенные и определяемые пользователем операторы, которые работают с ненулевыми типами значенийтакже для использования с обнуляемыми формами этих типов. Поднятые операторы состоят из предопределенных и определяемых пользователем операторов, которые отвечают определенным требованиям, как описано ниже:

...

  • Для операторов равенства

    ==  !=
    

существует поднятая форма оператора, если оба типа операндов являются необнуляемыми типами значений и если тип результата равен bool. Поднятая форма создается путем добавления одного модификатора ? к каждому типу операнда. Поднятый оператор считает два нулевых значения равными, а нулевое значение неравным любому ненулевому значению. Если оба операнда не равны NULL, оператор поднятого оператора разворачивает операнды и применяет базовый оператор для получения результата bool.

Вы не используете оператор:

bool ==(ulong left, ulong right)

Вы используете поднятый оператор:

bool ==(ulong? left, ulong? right)

Этот оператор принимает два ulong? параметра и возвращает true, если оба имеют значение NULL или оба имеют ненулевое значение и имеют одинаковое значение.


Вы, вероятно, смотрите на Visual Studio, которая действительно показывает вам что-то запутанное в этом случае:

Visual Studio screenshot

Донне путайтесь с этим - как @mjwills указал в комментариях, это известная проблема .


Если вы напишите это:

public bool M(ulong a, ulong? b) {
    return a == b;
}

Затем компилятор выдает следующий код:

public bool M(ulong a, ulong? b)
{
    ulong? num = b;
    return (a == num.GetValueOrDefault()) & num.HasValue;
}

num.GetValueOrDefault() возвращает 0, если b равно null, в противном случае значение b. Таким образом, M возвращает true тогда и только тогда, когда b не равно нулю и имеет то же значение, что и a.

SharpLab

7 голосов
/ 15 октября 2019

Если мы используем оператор == между выражением ulong и выражением ulong?, То используется перегрузка оператора bool ulong (ulong left, ulong right).

Большая часть проблемы заключается в том, что в IntelliSense Visual Studio неправильно отображается используемый оператор ulong == (при наведении курсора на ==).

Это ошибка согласно https://github.com/dotnet/roslyn/issues/21494. Это не на самом деле , использующий этот оператор.

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

...