Почему / Как .Net позволяет мне отрицать значение Nullable , которое является нулевым?

Я обнаружил, что смотрю на код, который выглядит примерно так:

private double? _foo;

public double? Foo
{
    get { return _foo; }
    set { Baz(-value); }
}

public void Baz(double? value)
{
    // Perform stuff with value, including null checks
}

И в тесте у меня было следующее:

[Test]
public void Foo_test()
{
    ...
    Foo = null;
    ...
}

Я ожидал, что тест завершится неудачно (выброс), так как я думал что вы действительно не можете применить унарный минус к null , что, как я полагал, произойдет в сеттере Foo . Однако случилось непредвиденное, и тест не провалился .

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

(И прежде, чем кто-то укажет на очевидное: да, отрицание определенно должно быть втиснуто внутрь Baz .)

Edit and follow up

Итак, я благодарен за вклад Джона Скита и ДжаредПара, которые оба ответили на часть моего вопроса Как . После некоторого поиска в Google я нашел это сообщение в блоге Эрика Липперта, объясняющее математическое определение «поднятого» , которое имеет смысл. Я также прочитал соответствующие части спецификации языка, которые довольно просто объясняют механику подъема в C #.

В частности, теперь я знаю, что в начале процесса подъема операнда выполняется проверка на нуль, и если операнд равен нулю, нуль будет результатом применения оператора (в моем случае унарный минус). Итак, -null равно null .

Теперь к части вопроса «Почему». Если я определю свой собственный (унарный) оператор - в классе (в котором я инвертирую значение в оболочке), и вызовите этот оператор для нулевой ссылки, я получу NullReferenceException . Почему «подъем» ведет себя иначе? На самом деле меня интересуют причины этого дизайнерского решения. Я определенно не против этого решения.

5
задан Christoffer Lette 12 December 2010 в 22:58
поделиться