Зачем присваивать null в тернарном операторе не удается: неявное преобразование между нулем и int?

Это не удается с помощью There is no implicit conversion between 'null' and 'int'

long? myVar = Int64.Parse( myOtherVar) == 0 ? null : Int64.Parse( myOtherVar);

Однако это преуспевает:

if( Int64.Parse( myOtherVar) == 0)
    myVar = null;
else
    myVar = Int64.Parse( myOtherVar);

Есть ли способ сделать тройной оператор успешным?

Ответы

Ответ 1

Компилятор игнорирует левую сторону при определении типа правой части. Поэтому, когда он пытается вывести тип

Int64.Parse(myOtherVar) == 0 ? null : Int64.Parse(myOtherVar)

он делает это, не обращая внимания на то, что левая часть a long?. Чтобы определить тип правой части, он отмечает, что

Int64.Parse(myOtherVar)

является long и теперь пытается увидеть, является ли null или неявно преобразован в long. Поскольку он не может, вы получите сообщение об ошибке, которое вы видите.

Из раздела 7.14 спецификации С#:

Условное выражение формы b ? x : y....

Второй и третий операнды x и y оператора ?: управляют типом условного выражения.

(1) Если x имеет тип x и y имеет тип y, то

а. Если неявное преобразование (§6.1) существует от x до y, но не от y до x, то y является типом условного выражения.

б. Если неявное преобразование (§6.1) существует от y до x, но не от x до y, то x является типом условного выражения.

с. В противном случае тип выражения не может быть определен, и возникает ошибка времени компиляции.

(2) Если только один из x и y имеет тип, и оба x и y, из которых неявно конвертируются в этот тип, то это тип условного выражения.

(3) В противном случае тип выражения не может быть определен, и возникает ошибка времени компиляции.

Обратите внимание, что мы находимся в ситуации (2), где x есть null и не имеет типа, а y - Int64.Parse(myOtherVar) и имеет тип long. Обратите внимание, что x неявно конвертируется в тип y. Поэтому и (1), и (2) терпят неудачу выше, и мы приводим к (3), что приводит к ошибке времени компиляции, которая вдохновила ваш вопрос. Обратите внимание на неявный вывод из сказанного выше, что левая часть не играет роли в определении типа правой части.

Чтобы исправить это, замените

Int64.Parse(myOtherVar)

с

(long?)Int64.Parse(myOtherVar)

Теперь, почему

myVar = null;

в порядке, где myVar объявлен как long?, потому что компилятор знает, что существует неявное преобразование от null до long?.

Наконец, Int64.Parse будет бросать, если myOtherVar не может быть проанализирован на long. Обратите внимание, что вы также выполняете синтаксический анализ дважды, что необязательно. Лучшая модель

long value;
if(Int64.TryParse(myOtherVar, out value)) {
    myVar = value == 0 ? null : (long?)value;
}
else {
    // handle case where myOtherVar couldn't be parsed
}

Ответ 2

Использование вашего оператора возвращает Int64, а не nullable, из-за последней части тройного оператора. Он может работать, если вы это сделаете:

long? myVar = Int64.Parse( myOtherVar) == 0 ? null :
   (long?)Int64.Parse( myOtherVar);

Итак, вместо этого вы возвращаете long?, поэтому null не нужно преобразовывать в Int64

Кроме того, вы дважды конвертируете значение в свой код без необходимости (один раз для проверки и один раз для получения значения). Ваш код может быть лучше:

long? tempVar = Int64.Parse(myOtherVar);
long? myVar = tempVar==0? null : tempVar;

Ответ 3

Я уверен, что вы хотели сказать:

  myVar = value == 0 ? null : (long?)value;

вместо

  myVar = value == 0 ? null : value;

Мне понравилось использование переменной "out". Спасибо.

Ответ 4

Это будет работать:

long? myVar = (long?)myOtherVar == 0 ? null : (long?)myOtherVar;

.. для тех, кто любит короткие ответы.

Ответ 5

Компилятор пытается оценить выражения слева направо

long? myVar = Int64.Parse( myOtherVar) == 0 ? null : Int64.Parse( myOtherVar);

int64.parse возвращает значение long не длинное значение nullable. поэтому нет преобразования между null и Int64.Parse( myOtherVar); Итак, попробуйте этот

long? myVar = Int64.Parse(myOtherVar) == 0 ? (long?) null : Int64.Parse(myOtherVar);

OR
long? myVar = Int64.Parse(myOtherVar) == 0 ? null : (long?) Int64.Parse(myOtherVar);