2011-10-19 10 views
9

Есть ли кто-нибудь, кто может объяснить мне это странное поведение?Почему я должен явно окружать «unchecked»?

int i = 0x1234; 
    byte b1 = (byte)i; 
    byte b2 = (byte)0x1234;   //error: const value '4660' can't convert to byte (use unchecked) 
    byte b3 = unchecked((byte)0x1234); 
    byte b4 = checked((byte)i);  //throws 
    byte b5 = (byte)(int)0x1234; //error: same as above 

ПРИМЕЧАНИЕ: Это пустое консольное приложение, с NO арифметическая проверка включена (по умолчанию). Спасибо всем заранее.

EDIT: Я должен быть достаточно ясным, но не для всех.

Я знаю, что слово не может вписаться в байт. Но по умолчанию программа C# допускает определенные «опасные» операции, прежде всего по причине производительности.

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

Мое удивление было о ошибке времени компиляции выше: компиляция b1 cast/assign, b2 не может скомпилировать. По-видимому, нет никакой разницы, потому что оба типа Int32 имеют одинаковое значение.

Надеюсь, теперь это ясно.

+3

Я не говорю C#, и я не знаю, что означает «checked» и «unchecked», но я знаю, что вы не можете вставить четырехзначный шестнадцатеричный номер в байте. –

+1

Какое поведение «странно» для вас? Вы дали нам ** шаги для воспроизведения ** и ** фактического результата **, но не ** ожидаемого результата **. – AakashM

ответ

11

Вы споткнувшись часть раздела 7.19 в C# 4 спецификации:

Если постоянное выражение явно не помещается в unchecked контексте перетоки, которые возникают в арифметических операциях интегрального типа и преобразования во время оценка времени компиляции выражения всегда вызывает ошибки времени компиляции.

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

К примеру, в этом случае вы теряете информацию - это будет эквивалентно

byte b3 = 0x34; 

так что вы бы обычно быть лучше просто указать, что, чтобы дать вам четкое код, который Безразлично 'вводить в заблуждение читателя. Это относительно редко, что вы хотите переполняться в константе - большую часть времени вы должны просто указать действительное значение.

+3

Вы говорите, как юрист, цитирующий раздел 7.19 спецификации C# 4. : D – Otiel

+0

Для меня все в порядке, но почему компилятор не учитывает также «арифметическое переполнение»? В любом случае, спасибо: это было просто любопытство, на которое я столкнулся. –

+0

@MarioVernari: поскольку это предназначено для изменения поведения времени выполнения - большинство C# -кодов, вероятно, построено с этим значением по умолчанию, но большинство разработчиков все равно должны заботиться о переполнении * констант *. –

1

Это не странное поведение, допустимый диапазон для переменного типа данных byte является 0-255, но при преобразовании 0x1234 значения HEX в десятичную систему вы получили 4660. Так unchecked используется для управления арифметическими операциями и преобразованиями для проверки переполнения.

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

Подводя итог, вы должны использовать unchecked, когда конечное значение целочисленных операций не имеет значения, но может произойти переполнение.

1

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

byte b1 = (byte)i; вызовет исключение переполнения или отливки во время выполнения.

byte b2 = (byte)0x1234; недействителен, так как вы не можете хранить значения, превышающие 0xFF, в байте.

byte b3 = unchecked((byte)0x1234); поместит либо 0x34, либо 0x12 (в зависимости от реализации CLR) в b3, а другой байт переполнится.

byte b4 = checked((byte)i); такая же, как byte b1 = (byte)i;

byte b5 = (byte)(int)0x1234; будет отбрасывать 0x1234 к междунар, а затем попытаться бросить его в байт. Опять же, вы не можете преобразовать 0x1234 в байт, потому что он слишком велик.

+0

Ну, вы частично правы, но совсем нет. Это правда, что избежать проверок - это опасная практика, но вы также должны использовать их с небольшим мозгом, ИМХО. Это НЕправда, что ваше первое назначение вызывает исключение. Он будет выдаваться, только если вы включите «арифметическую проверку» (по умолчанию отключено). Третье назначение, я думаю, ошибочно: он должен всегда возвращаться 0x12. Четвертый: те же соображения первого. Пятое: то же, что и второе. Cheers –

+0

Третий всегда будет возвращать 0x34, а не 0x12. И первый вызовет только исключение, если проверка включена и если значение находится вне диапазона 0-255. – phoog

+0

Спасибо за исправления ребята :) – Polynomial