Двоичные сдвиги Разница между VB.NET и С#

Я просто нашел интересную проблему между переводом некоторых данных:

VB.NET: CByte(4) << 8 Возвращает 4

Но С#: (byte)4 << 8 Возвращает 1024

А именно, почему VB.NET: (CByte(4) << 8).GetType() возвращает тип {Name = "Byte" FullName = "System.Byte"}

Тем не менее С#: ((byte)4 << 8).GetType() возвращает тип {Name = "Int32" FullName = "System.Int32"}

Есть ли причина, почему эти два рассматривают двоичный сдвиг одинаково? Следуя за этим, есть ли способ сделать смещение бит С# так же, как VB.NET(чтобы сделать VB.NET таким же, как С#, что вы просто делаете CInt(_____) << 8)?

Ответ 1

В соответствии с http://msdn.microsoft.com/en-us/library/a1sway8w.aspx байт не имеет < < < определенный для него для С# (только int, uint, long и ulong. Это означает, что он будет использовать преобразование implciit в тип, который он может использовать, чтобы он преобразовывал его в int перед выполнением сдвига бит.

http://msdn.microsoft.com/en-us/library/7haw1dex.aspx говорит, что VB определяет операцию в байтах. Чтобы предотвратить переполнение, он применяет маску к вашему сдвигу, чтобы привести ее в соответствующий диапазон, поэтому на самом деле в этом случае вообще ничего не происходит.

Что касается того, почему С# не определяет переключение на байты, я не могу сказать вам.

Чтобы заставить его вести себя одинаково для других типов данных, вам нужно просто замаскировать свой номер сдвига на 7 для байтов или 15 для шорт (см. вторую ссылку для информации).

Ответ 2

Чтобы применить то же самое в С#, вы должны использовать

static byte LeftShiftVBStyle(byte value, int count)
{
    return (byte)(value << (count & 7));
}

относительно того, почему VB использовал этот подход... просто другой язык, разные правила (это естественное продолжение того, как С# обрабатывает смещение int/& 31 и long/& 63, чтобы быть справедливым).

Ответ 3

Крис уже прибил его, vb.net определил операторы сдвига для байтов и коротких типов, С# - нет. Спецификация С# очень похожа на C, а также хорошее совпадение для определений MSIL для OpCodes.Shl, Shr и Shr_Un, они принимают только операнды int32, int64 и intptr. Соответственно, любые байты или короткие операнды сначала преобразуются в int32 с их неявным преобразованием.

Это ограничение, с которым должен работать компилятор vb.net, требует генерации дополнительного кода для создания байта и коротких конкретных версий операторов. Оператор байта реализуется следующим образом:

Dim result As Byte = CByte(leftOperand << (rightOperand And 7))

и короткий оператор:

Dim result As Short = CShort(leftOperand << (rightOperand And 15))

Соответствующая операция С#:

Dim result As Integer = CInt(leftOperand) << CInt(rightOperand)

Или CLng(), если требуется. Неявный код С# заключается в том, что программисту всегда нужно вернуть результат обратно к желаемому типу результата. Есть много вопросов о том, что от программистов, которые не считают это очень интуитивным. У VB.NET есть еще одна функция, которая делает автоматическое кастинг более живучим, по умолчанию включена проверка переполнения. Хотя это не относится к сменам.