C# Null Условный оператор альтернативы (условное присвоение)?
Нулевой условный оператор C# допускает полезное короткое замыкание:
double? range = (unit as RangedUnit)?.WeaponRange;
К сожалению, условно-нулевой оператор нельзя использовать одинаково для короткого назначения, потому что он возвращает значение (которое нельзя использовать в левостороннем назначении):
(unit as RangedUnit)?.PreferredTarget = UnitType.Melee;
в результате возможный альтернативный синтаксис:
if (unit is RangedUnit)
{
(unit as RangedUnit).PreferredTarget = UnitType.Melee;
}
Если компилятор знает, что RangedUnit является ссылочным типом (а не типом значения), почему он не может условно выполнить сокращенный синтаксис
refTypeInstance?.SomeField = value;
(т. е. если refTypeInstance имеет значение null, просто ничего не делать. Если refTypeInstance не равен null, выполнить инструкцию)
ОБНОВЛЕНИЕ (ЗАКЛЮЧЕНИЕ):
- Нулевой условный оператор нельзя использовать в левой части оператора присваивания, потому что это нарушило бы ожидаемую логику оценки дерева выражений оператора присваивания (короткое замыкание операции присваивания и ее полное отсутствие)
- Идеальным решением является новый оператор условного присваивания (выполняется только в том случае, если левая часть присваивания не равна нулю), по сути, "если не пусто, одно присваивание - один вкладыш"
2 ответа
Поведение, которое вы ожидаете:
(т. е. если refTypeInstance имеет значение null, просто ничего не делать. Если refTypeInstance не равен null, выполнить инструкцию)
Это невозможно из-за того, как работают операторы. Более конкретно, у вас есть проблема с приоритетом операторов и как деревья выражений формируются на основе этого:
В заявлении
(unit as RangeUnit).PreferredTarget = UnitType.Melee;
Оператор присваивания (=
) будет в корне дерева выражений с левым и правым выражениями в качестве ветвей.
NullReferenceException
будет происходить при оценке левой руки (до назначения). На данный момент компилятор уже начал оценивать=
, С оператором разыменования (.
) закину NullReferenceException
во время выполнения компилятору безопасно просто продолжить синтаксический анализ дерева выражений.
С другой стороны, если это утверждение разрешено:
(unit as RangeUnit)?.PreferredTarget = UnitType.Melee;
... компилятор должен выдать код, чтобы проверить, является ли значение refTypeInstance
нулевой. Это может быть сделано, но проблема в том, что будет делать компилятор с деревом выражений, через которое он в данный момент проходит? Это не может просто продолжаться, как в первом примере, потому что это должно было бы отказаться от =
вверх по дереву выражений и тому .
вниз по дереву. В основном нужно было бы вставить два варианта синтаксического анализа дерева, один, когда слева от ?.
является null
и один, когда это не так. Это, однако, было бы изменением потока управления, что определенно не то, что вы ожидаете от оператора.
Или, по-другому: когда ?.
просто закорачивает оценку операторов вниз по ее ветви дерева выражений, вы можете считать это ожидаемым поведением. Но в этом случае это изменит поведение оператора выше в дереве выражений, чего вы точно не ожидаете.
Потому что они не делают то же самое,
Первый фрагмент вернет ноль, если единица равна нулю (или не является единицей дальнего боя).
Если бы это произошло, когда вы пытались что-то установить, вы бы не смогли установить значение null в значение (и в итоге вы получите ошибку).