Этот вопрос уже имеет ответ здесь:
Почему делает следующее повышение ошибка времени компиляции: 'Не может неявно преобразовать тип 'интервал' в 'байт':
byte a = 25;
byte b = 60;
byte c = a ^ b;
Это имело бы смысл, если бы я использовал arithmentic оператор, потому что результат + b мог быть больше, чем можно сохранить в единственном байте.
Однако применение этого к оператору XOR бессмысленно. XOR здесь это битовая операция, которая никогда не может переполнять байта.
использование броска вокруг обеих работ операндов:
byte c = (byte)(a ^ b);
Я не могу дать вам объяснение, но могу сказать, почему компилятор имеет такое поведение с точки зрения правил, которым компилятор должен следовать ( что может быть не совсем то, что вам интересно знать).
Из старой копии спецификации C # (мне, вероятно, следует загрузить более новую версию) добавлено выделение:
14.2.6.2 Двоичные числовые рекламные предложения Этот пункт является информативным.
Двоичное числовое повышение происходит для операндов предопределенных
+
,?
,*
,/
,%
,&
,|
,^
,==
,! =
,>
,<
,> =
и<=
бинарные операторы. Двоичное числовое продвижение неявно преобразует оба операнда в общий тип, который в случае нереляционных операторов также становится результатом {{1} } тип операции. Двоичное числовое продвижение состоит из применения следующих правил в том порядке, в котором они появляются здесь:
- Если один из операндов имеет десятичный тип, другой операнд будет {{1} }} преобразуется в тип decimal, или ошибка времени компиляции возникает, если другой операнд имеет тип float или double.
- В противном случае, если один из операндов имеет тип double, другой операнд преобразуется в тип double.
- В противном случае, если один из операндов имеет тип float, другой операнд преобразуется в тип float.
- В противном случае, если один из операндов имеет тип ulong, другой операнд преобразуется в тип ulong, или возникает ошибка времени компиляции, если другой операнд имеет введите sbyte, short, int, или long.
- В противном случае, если один из операндов имеет тип long, другой операнд преобразуется в тип long.
- В противном случае, если один из операндов имеет тип uint, а другой операнд имеет тип sbyte, short или int, оба операнда преобразуются в тип long.
- В противном случае, если один из операндов имеет тип uint, другой операнд преобразуется в тип uint.
- В противном случае оба операнда преобразуются в тип int .
Таким образом, в основном операнды, меньшие, чем int
, будут преобразованы в int
для этих операторов (и результатом будет int
для нереляционных опс).
Я сказал, что не могу дать вам объяснение; однако я сделаю предположение об одном - я думаю, что разработчики C # хотели убедиться, что операции, которые могут потерять информацию в случае сужения, должны иметь эту операцию сужения, явно выраженную программистом в форме приведения. Например:
byte a = 200;
byte b = 100;
byte c = a + b; // value would be truncated
Хотя такого рода усечение не произойдет при выполнении операции xor между двумя байтовыми операндами, я думаю, что разработчики языка, вероятно, не хотели иметь более сложный набор правил, где некоторые операции потребуют явного слепки и прочее нет.
Небольшое примечание: приведенная выше цитата является «информационной», а не «нормативной», но она охватывает все случаи в удобной для чтения форме.Строго говоря (в нормативном смысле), причина того, что оператор ^
ведет себя таким образом, заключается в том, что ближайшая перегрузка для этого оператора при работе с операндами байтом
является (из 14.10.1 "Целое число логические операторы "):
int operator ^(int x, int y);
Поэтому, как объясняется в информативном тексте, операнды повышаются до int
, и получается результат int
.
Похоже, это потому, что в спецификациях языка C # это определено для целых и длинных http://msdn.microsoft.com/en-us/library/aa691307%28v=VS.71%29.aspx
Итак, что на самом деле происходит, этот компилятор неявно преобразует байтовые операнды в int, потому что таким образом не происходит потери данных. Но результат (int) не может быть понижен без потери данных (неявно). Итак, вам нужно явно сообщить компилятору, что вы знаете, что делаете!
У программиста-полубога из Microsoft есть ответ: http://blogs.msdn.com/oldnewthing/archive/2004/03/10/87247.aspx
И, возможно, это больше о дизайне компилятора. Они упрощают компилятор, обобщая процесс компиляции, ему не нужно смотреть на оператор операндов, поэтому побитовые операции сосредоточены в той же категории, что и арифметические операторы. Таким образом, подвергается расширению типа
Ссылка мертва, архив здесь:
Я думаю, это потому, что оператор XOR определен для логических и целых чисел.
Приведение результата из целочисленного результата к байту - это преобразование с потерей информации; следовательно, требуется явное приведение (кивок программиста).
Мне показалось, что я вспомнил популярный вопрос об этом.
Это больше связано с правилами, окружающими неявное и явное приведение в спецификации CLI. Целое число (int = System.Int32 = 4 байта) шире, чем байт (1 байт, очевидно!). Поэтому любое приведение от int к байту потенциально является сужающим приведением. Поэтому компилятор хочет, чтобы вы сделали это явным.
Что касается того, почему два байта должны быть преобразованы в ints для выполнения XOR?
Если вы хотите покопаться в этом, 12.1.2 CLI Spec (раздел I) описывает тот факт, что в стеке оценки могут существовать только int или long. Все более короткие интегральные типы должны быть расширены во время оценки.
К сожалению, я не могу найти подходящую ссылку непосредственно на CLI Spec - у меня есть локальная копия в формате PDF, но я не могу вспомнить, откуда я ее взял.