Ответ 1
Я не могу дать вам обоснование, но я могу понять, почему компилятор имеет такое поведение с точки зрения правил, которым должен следовать компилятор (что может быть не совсем то, что вам интересно знать).
Из старой копии спецификации С# (возможно, я должен загрузить более новую версию), добавлено выделение:
14.2.6.2 Двоичные числовые акции Этот раздел является информативным.
Двоичное числовое продвижение происходит для операнды предопределенных
+
,?
,*
,/
,%
,&
,|
,^
,==
,!=
,>
,<
,>=
и<=
двоичные операторы, двоичный числовое продвижение неявно преобразуется оба операнда к общему типу, которые, в случае нереляционной операторов, также становится результатом тип операции. Двоичный цифровой продвижение состоит в применении следуя правилам, в порядке, в котором они здесь:
- Если один из операндов имеет тип decimal, другой операнд преобразуется в десятичный тип или ошибка компиляции возникает, если другая операнд имеет тип float или double.
- В противном случае, если любой из операндов имеет тип double, другой операнд преобразованный в тип double.
- В противном случае, если любой операнд имеет тип float, другой операнд преобразуется в тип float.
- В противном случае, если один из операндов имеет тип ulong, другой операнд преобразуется в тип ulong или ошибка компиляции возникает, если другая операнд имеет тип sbyte, short, int, или долго.
- В противном случае, если любой из операндов имеет тип long, другой операнд преобразованный в тип long.
- В противном случае, если любой операнд имеет тип uint, а другой операнд тип sbyte, short или int, оба операнды преобразуются в тип long.
- В противном случае, если любой операнд имеет тип uint, другой операнд преобразован в тип uint.
- В противном случае оба операнда преобразуются в тип int.
Таким образом, в основном операнды, меньшие, чем int
, будут преобразованы в int
для этих операторов (и результат будет int
для нереляционных ops).
Я сказал, что не могу дать вам обоснования; однако я сделаю предположение о том, что разработчики С# хотели удостовериться, что операции, которые могут потерять информацию, если сузить, должны были бы выполнять эту операцию сужения, явно выраженную программистом в форме приведения. Например:
byte a = 200;
byte b = 100;
byte c = a + b; // value would be truncated
Хотя такого рода усечение не произойдет при выполнении операции xor между двумя операндами байтов, я думаю, что разработчики языка, вероятно, не хотели иметь более сложный набор правил, в которых для некоторых операций требуются явные приведения и другие нет.
Небольшое примечание: приведенная выше цитата "информационная" не "нормативная", но охватывает все случаи в легко читаемой форме. Строго говоря (в нормативном смысле) причина, по которой ведет себя оператор ^
, заключается в том, что ближайшая перегрузка для этого оператора при работе с операндами byte
(из 14.10.1 "Целые логические операторы" ):
int operator ^(int x, int y);
Поэтому, как поясняется информативным текстом, операнды повышаются до int
и получается результат int
.