Простой и правильный ответ «потому что Спецификация языка C# так говорит».
Очевидно, вы не удовлетворены этим ответом и хотите знать «почему это так». Вы ищете «надежные и/или официальные источники», это будет немного сложно. Эти проектные решения были сделаны давно, 13 лет - много жизни собак в разработке программного обеспечения. Они были сделаны «старыми таймерами», как их называет Эрик Липпер, они перешли к более крупным и лучшим вещам и не публикуют ответы здесь, чтобы предоставить официальный источник.
Это может быть выведено, однако, с риском просто быть заслуживающим доверия. Любой управляемый компилятор, такой как C#, имеет ограничение на то, что ему нужно сгенерировать код для виртуальной машины .NET. Правила для которых тщательно (и вполне читаемы) описаны в спецификации CLI. Это спецификация Ecma-335, вы можете скачать ее бесплатно from here.
Перейдите к разделу 3.1, главе 3.1 и 3.2. Они описывают две инструкции IL, доступные для выполнения добавления, add
и add.ovf
. Нажмите ссылку на таблицу 2 «Двоичные числовые операции», в которой описаны, какие операнды допустимы для этих инструкций IL. Обратите внимание, что здесь есть всего несколько типов. байтовый и короткий, а также все неподписанные типы отсутствуют. Допускается только int, long, IntPtr и с плавающей запятой (float и double). С дополнительными ограничениями, отмеченными x, вы не можете добавить int к длинному, например.Эти ограничения не являются полностью искусственными, они основаны на том, что вы можете сделать достаточно эффективно на доступном оборудовании.
Любой управляемый компилятор должен иметь дело с этим, чтобы генерировать действительный IL. Это не сложно, просто преобразуйте ushort в более крупный тип значения, который находится в таблице, преобразование, которое всегда действует. Компилятор C# выбирает int, следующий более крупный тип, который появляется в таблице. Или, вообще говоря, конвертируйте любой из операндов в следующий наибольший тип значения, чтобы они оба имели один и тот же тип и отвечали ограничениям в таблице.
Теперь возникает новая проблема, проблема, с которой программисты на C# довольно ошеломлены. Результат добавления относится к продвинутому типу. В вашем случае это будет int. Таким образом, добавление двух значений ushort, скажем, 0x9000 и 0x9000, имеет вполне допустимый результат int: 0x12000. Проблема в том, что это значение, которое не укладывается в пользовательское пространство. Значение переполнено. Но он не сделал переполнения в расчете IL, он переполняется только тогда, когда компилятор пытается втиснуть его обратно в ushort. 0x12000 усекается до 0x2000. Загадочная другая ценность, которая имеет смысл только при подсчете с 2 или 16 пальцами, а не с 10.
Примечательно, что команда add.ovf не справляется с этой проблемой. Это инструкция для автоматической генерации исключения переполнения. Но это не так, фактический расчет на преобразованных ints не переполнялся.
Это то, где вступает в игру реальное дизайнерское решение. Похоже, старожилы решили, что просто усечение результата int для ushort было ошибкой. Это определенно. Они решили, что вы должны признать, что вы знаете, что добавление может переполняться и что все в порядке, если это произойдет. Они сделали вашей проблемой, главным образом потому, что они не знали, как сделать это и все еще генерировать эффективный код. Вы должны бросить. Да, это безумие, я уверен, что вы тоже не хотели этой проблемы.
Совершенно очевидно, что разработчики VB.NET приняли другое решение проблемы. Они действительно сделали своей проблемой и не пропустили доллар. Вы можете добавить два UShorts и назначить их в UShort без трансляции. Разница в том, что компилятор VB.NET фактически генерирует дополнительно IL, чтобы проверить условие переполнения. Это не дешевый код, делает каждое короткое дополнение примерно в 3 раза медленнее. Но в остальном причина, объясняющая, почему Microsoft поддерживает два языка, которые в ином случае имеют схожие возможности.
Короче говоря: вы платите цену, потому что используете тип, который не очень хорошо сочетается с современными архитектурами процессора. Что само по себе является действительно хорошим основанием для использования uint вместо ushort. Получение тяги из Ushort затруднено, вам нужно много их, прежде чем затраты на их манипулирование - весит экономию памяти. Не только из-за ограниченной спецификации CLI, ядро x86 занимает дополнительный цикл процессора, чтобы загрузить 16-битное значение из-за байта префикса операнда в машинный код. На самом деле не уверен, что это все еще так, но когда-то он возвращался, когда я все еще обращал внимание на циклы подсчета. Собака год назад.
Обратите внимание, что вы можете чувствовать себя лучше об этих уродливых и опасных забросов, позволяя C# компилятор генерировать тот же код, который генерирует компилятор VB.NET. Таким образом, вы получаете исключение OverflowException, когда литье оказалось неразумным. Используйте «Проект»> «Свойства»> вкладка «Строка»> «Дополнительно»> отметьте флажок «Проверить арифметическое переполнение/недополнение». Только для сборки Debug. Почему этот флажок не включен автоматически шаблоном проекта, является еще одним очень мистифицирующим вопросом, решение, которое было сделано слишком давно.
http://bytes.com/topic/c-sharp/answers/256857-does-ushort-ushort-return-int-value (см. Ответ J.Skeets) –
Я обновил свой ответ из спецификаций C# от Microsoft – Habib