?. оператор в 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!
Другие вопросы по тегам