См. Раздел 7.3.7 из спецификация c:
Поднятые операторы разрешают предопределенные и определяемые пользователем операторы, которые работают с необнуляемыми типами значений, которые также могут использоваться с обнуляемыми формами этих типов Поднятые операторы состоят из предопределенных и определенных пользователем операторов, которые отвечают определенным требованиям, как описано ниже:
- Для унарных операторов
+ ++ - -- ! ~
поднятая форма оператора существует, если оба типа операнда и результата являются типами значений, отличными от NULL. Поднятая форма создается путем добавления одного модификатора ?
к операнду и типу результата. Поднятый оператор выдает нулевое значение, если операнд нулевой. В противном случае поднятый оператор разворачивает операнд, применяет нижележащий оператор и упаковывает результат.
(выделение)
Итак:
bool? x = null;
bool? y = !x;
Следует этому правилу. Мы используем поднятую форму унарного оператора !
, что приводит к null
, если значение, к которому он применяется, равно null
.
!null
не допускается, потому что null
не относится к типу Nullable<T>
. Однако !(bool?)null
работает (хотя и выдает предупреждение компилятора).
!
действительно имеет более высокий приоритет, чем ??
, см. Раздел 7.3.1