Почему выражение switch определяет тип выражения из окружающего контекста, а другие выражения с неоднозначной типизацией - нет? - PullRequest
3 голосов
/ 05 августа 2020

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

For Например, это не компилирует

double a = new Random().Next(2) == 0 ? (short)1 : (uint)1;

, потому что компилятор «не смотрит» на часть double a при проверке типа и видит, что выражение имеет тип либо short или uint. Выражение не может быть двух типов, поэтому выводится ошибка. Это отлично. Довольно хорошо известно, что C# не учитывает тип переменной, которую вы назначаете, как и в дженериках:

static T F<T>() => default(T);
double d = F(); // can't infer that T is double

Однако , выражения switch ломаются это «правило». Если я перепишу первый фрагмент кода с помощью выражений переключения:

double a = (new Random().Next(2) == 0) switch {
    true => (short)1,
    false => (uint)1
};

Затем он внезапно компилируется! В отличие от первого фрагмента кода, компилятор, похоже, обратил внимание на часть double a и понял, что мне нужен double. Я попытался посмотреть docs для выражений переключателя, но там не упоминается, что он будет выполнять какие-либо автоматические c преобразования в тип результата или что-то подобное.

Почему C# так ли умен, когда работаете с выражениями переключателя, но не с другими типами выражений (такими как тернарный оператор)?

1 Ответ

1 голос
/ 05 августа 2020

Из предложения C# lang для выражений переключателя;

Тип switch_expression - лучший общий тип выражений, появляющихся в справа от => токенов switch_expression_arms, если такой тип существует, и выражение в каждом плече выражения switch может быть неявно преобразовано в этот тип. Кроме того, мы добавляем новое преобразование выражения переключателя, которое является предопределенным неявным преобразованием из выражения переключателя в каждый тип T, для которого существует неявное преобразование из выражения каждой руки в T.

Лучшее общий тип?

В некоторых случаях необходимо вывести общий тип для набора выражений. В частности, таким образом находятся типы элементов массивов с неявно типизированными типами и типы возвращаемых анонимных функций с телами блоков.

Интуитивно, учитывая набор выражений E1...Em, этот вывод должен быть эквивалентен вызову метод

Tr M<X>(X x1 ... X xm)

с Ei в качестве аргументов.

Точнее, вывод начинается с переменной нефиксированного типа X. Затем выводы типа вывода выполняются от каждого Ei до X. Наконец, X фиксирован, и в случае успеха результирующий тип S является лучшим общим типом для выражений. Если такой S не существует, выражения не имеют наилучшего общего типа

Так как это не компилируется, с ошибкой «нет лучшего типа ..»;

var x = (id == 0) switch
{
    true => (short)1,
    false => (uint)1
};

Ваш example double x ... ограничивает тип вывода, изменяя способ вывода типов выражений переключения. Но это всего лишь предположение.

В то время как условный оператор имеет очень строгие правила;

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

  • Если x имеет тип X, а y имеет тип Y, то
    • Если существует неявное преобразование (неявные преобразования) из X в Y, но не из Y в X, тогда Y - это тип условного выражения.
    • Если существует неявное преобразование (неявные преобразования) из Y в X, но не из X в Y, то X является типом условное выражение.
    • В противном случае тип выражения не может быть определен и возникает ошибка времени компиляции.
  • Если только один из x и y имеет тип, и как x, так и y, of неявно преобразуются в этот тип, тогда это тип условного выражения.
  • В противном случае невозможно определить тип выражения, и возникает ошибка времени компиляции.

TL; DR; правила вывода типов / продвижения очень разные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...