?. оператор в C# не компилируется по неизвестной причине
В следующем коде один из двух вариантов не компилируется:
class C
{
public decimal DecimalField;
}
static C GetC() { return new C(); } //Can return null in reality.
C c = GetC(); //Get a C value from somewhere, this might be null
string toString1 = c?.DecimalField?.ToString(); //Does not compile.
string toString2 = (c?.DecimalField)?.ToString(); //Compiles.
Ошибка CS0023: оператор '?' не может быть применен к операнду типа 'десятичный'
Почему простая форма не компилируется?
Не было бы выражение c?.DecimalField
быть типа decimal?
? Это значение может быть нулевым, поэтому ?.
оператор должен подать заявку. Я совершенно уверен, что это так, потому что в этом коде:
var decimalValue = c?.DecimalField;
var
решает decimal?
в соответствии с IDE.
4 ответа
Это связано с тем, что оператор условного доступа имеет "короткое замыкание". То есть если ты пишешь a?.b.c
и выполнить его с a
являющийся null
то не только .b
не выполнено, но .c
также не выполняется.
Как следствие, когда вы пишете a?.b?.c
, тогда второй нуль-условный оператор доступа не о проверке, a
или же a.b
является null
, Речь идет только о проверке a.b
является null
, Так что если a.b
никогда не может быть null
Как и в вашем случае, не имеет смысла использовать оператор нулевого условия, поэтому язык этого не позволяет.
Это также объясняет, почему a?.b?.c
а также (a?.b)?.c
это не одно и то же.
Для получения дополнительной информации об этом вы можете прочитать заметки C# Language Design Meeting, где это было решено.
Тип decimal
это не обнуляемый тип. Поэтому ваше первое выражение не компилируется. Отличие от второго утверждения заключается в том, что внутренняя часть скобки уже может быть null
если c
было null
, Поэтому он компилируется.
Это может привести к null
значение: (c?.DecimalField)
Полученный тип System.Nullable<decimal>
или кратко написано decimal?
Тип decimal не может быть нулевым, поэтому оператор null-coalesce здесь не имеет смысла. Просто установите toString1 в какое-то значение.
Если вы хотите скомпилировать его во всех случаях, вам следует отредактировать DecimalField
который вы сравниваете с обнуляемым типом, добавив decimal ?
поставленный decimal
на вашем поле определения.
У вас есть три варианта.
Вы можете установить значение по умолчанию, он возвращает DecimalField
или же "0"
:
string toString = c?.DecimalField.ToString() ?? decimal.Zero.ToString();
Без значения по умолчанию возвращает DecimalField
или же null
:
string toString = c?.DecimalField.ToString();
Или вы можете сделать DecimalField
обнуляется, возвращается DecimalField
или же null
:
public decimal? DecimalField;
...
string toString1 = c?.DecimalField?.ToString(); //Compile now!