Несколько вещей.
Во-первых, условный оператор - это тернарный оператор, а не третичный оператор.
Во-вторых, я отмечаю, что в ваших образцах кода два образца кода, которые должны быть эквивалентными, не являются:
short foo;
if (isValid)
foo = -1;
else
getFoo();
это не то же самое, что
short foo = isValid ? (short)-1 : getFoo();
Первый оставляет foo неназначенным, если isValid имеет значение false. Последний назначает foo независимо от значения isValid.
Я предполагаю, что вы имели в виду
short foo;
if (isValid)
foo = -1;
else
foo = getFoo();
и, кроме того, getFoo () возвращает короткий.
Возникает вопрос, почему преобразование в условном операторе без приведения типа является недопустимым, но вследствие того, что оператор if является допустимым.
Это допустимо в выражении if, поскольку в разделе 6.1.9 спецификации указано:
Константное выражение типа int может быть преобразовано в тип sbyte, byte, short, ushort, uint или ulong, при условии, что значение константного выражения находится в пределах диапазона целевого типа.
-1 - это постоянное выражение типа int, которое находится в диапазоне short, поэтому его можно неявно преобразовать в short.
Так почему же форма условного выражения является подделкой?
Первое, что мы должны четко установить, - это правило, согласно которому тип условного выражения определяется его содержимым, а не его контекстом. Тип выражения в правой части присваивания не зависит от того, чему оно присваивается! Предположим, у вас есть
short M(short x){...}
int M(int x){...}
short y = M(-1);
Я не думаю, что вы ожидаете, что разрешение перегрузки скажет хорошо, я бы обычно выбирал M (int), потому что -1 - это int, но нет, я выберу M (short) вместо этого, потому что в противном случае присваивание не будет Работа. Разрешение перегрузки ничего не знает о том, куда идет результат. Его задача - определить правильную перегрузку на основе приведенных аргументов, а не на основе контекста вызова.
Определение типа условного выражения работает точно так же. Мы не смотрим на тип, к которому он собирается, мы смотрим на типы, которые есть в выражении.
Итак, мы установили, что тот факт, что это присвоено короткому значению, не имеет значения для определения типа выражения. Но остается вопрос: почему тип условного выражения int, а не короткий?
Это очень хороший вопрос. Перейдем к спец.
Второй и третий операнды, x и y, оператора?: Управляют типом условного выражения.
Если имеет тип X, а y имеет тип Y, тогда:
Если существует неявное преобразование из X в Y, но не из Y в X, то Y является типом условного выражения.
Если существует неявное преобразование из Y в X, но не из X в Y, то X - это тип условного выражения.
В противном случае невозможно определить тип выражения и возникает ошибка времени компиляции.
В этом случае оба операнда имеют тип. (Там есть словоблудие о том, имеет ли x тип ... для случая, когда у вас есть null или лямбда; у них нет типов!) Первый операнд имеет тип int, второй - тип short .
Неявное преобразование существует от short к int, но не от int к short. Следовательно, тип условного выражения - int, который нельзя присвоить short.
Можно сказать, что этот алгоритм не так хорош, как мог бы быть. Мы могли бы значительно усложнить алгоритм, чтобы справиться со всеми случаями, когда было два возможных типа кандидатов - в этом случае, int и short являются правдоподобными кандидатами, потому что обе ветви могут быть преобразованы как в int, так и в short , когда рассматриваются как конкретные выражения. , а не просто иметь типы. В этом случае мы могли бы сказать, что предпочтительным был меньший из двух типов.
(Иногда в C # мы говорим, что более общий из двух типов - лучший тип, но в этом случае вы хотите, чтобы мы выбрали более конкретный. Язык не согласован в этом конкретном аспекте дизайна, к сожалению; я лично предпочел бы, чтобы мы всегда выбирали более конкретный, но есть сценарии вывода типов, где сейчас это было бы критическим изменением.)
Я подумал о том, чтобы сделать это еще в 2006 году. При разработке поведения того, как LINQ работает с ситуациями, когда есть несколько типов на выбор, и один должен быть выбран как лучший, мы заметили, что условный оператор уже должен был решить эту проблему, и что, кроме того, , в C # 2 это не было реализовано в соответствии со спецификацией. По этому поводу велись долгие споры, и в итоге мы внесли некоторые незначительные изменения в спецификацию условного оператора, чтобы привести его в большее соответствие с его реализованным (и желаемым) поведением. Однако мы решили не вносить большие критические изменения в настройку алгоритма, чтобы использовать меньший из двух возможных типов, когда было несколько на выбор.
Некоторые размышления об этой проблеме см. В моих сообщениях за 2006 год:
person
Eric Lippert
schedule
30.06.2010
getFoo
? - person Oded   schedule 30.06.2010-1
в сокращенный. Его ошибка не в условности. - person SLaks   schedule 30.06.2010