Язык программирования C#9 и платформа .NET5
Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?)He удается неявно преобразовать тип int в short. Существует явное преобразование (возможно, пропущено приведение)
Проблема в том, что хотя метод
способен возвратить значениеAdd(), равное 60 000 (которое умещается в допустимый диапазон дляint), это значение не может быть сохранено в переменнойSystem.Int32потому что выходит за пределы диапазона допустимых значений для типаshort,. Выражаясь формально, среде CoreCLR не удалось применить сужающую операцию. Нетрудно догадаться, что сужающая операция является логической противоположностью расширяющей операции, поскольку предусматривает сохранение большего значения внутри переменной типа данных с меньшим диапазоном допустимых значений.shortВажно отметить, что все сужающие преобразования приводят к ошибкам на этапе компиляции, даже когда есть основание полагать, что такое преобразование должно пройти успешно. Например, следующий код также вызовет ошибку при компиляции:
// Снова ошибка на этапе компиляции!static void NarrowingAttempt(){byte myByte = 0;int myInt = 200;myByte = myInt;Console.WriteLine("Value of myByte: {0}", myByte);}Здесь значение, содержащееся в переменной типа
, благополучно умещается в диапазон допустимых значений для типаint(myInt); следовательно, можно было бы ожидать, что сужающая операция не должна привести к ошибке во время выполнения. Однако из-за того, что язык C# создавался с расчетом на безопасность в отношении типов, все-таки будет получена ошибка на этапе компиляции.byteЕсли нужно проинформировать компилятор о том, что вы готовы мириться с возможной потерей данных из-за сужающей операции, тогда потребуется применить явное приведение, используя операцию приведения
языка С#. Взгляните на показанную далее модификацию класса():Programclass Program{static void Main(string[] args){Console.WriteLine("***** Fun with type conversions *****");short numb1 = 30000, numb2 = 30000;// Явно привести int к short (и разрешить потерю данных).short answer = (short)Add(numb1, numb2);Console.WriteLine("{0} + {1} = {2}",numb1, numb2, answer);NarrowingAttempt();Console.ReadLine();}static int Add(int x, int y){return x + y;}static void NarrowingAttempt(){byte myByte = 0;int myInt = 200;// Явно привести int к byte (без потери данных).myByte = (byte)myInt;Console.WriteLine("Value of myByte: {0}", myByte);}}Теперь компиляция кода проходит успешно, но результат сложения оказывается совершенно неправильным:
***** Fun with type conversions *****30000 + 30000 = -5536Value of myByte: 200Как вы только что удостоверились, явное приведение заставляет компилятор применить сужающее преобразование, даже когда оно может вызвать потерю данных. В случае метода
это не было проблемой, т.к. значение 200 умещалось в диапазон допустимых значений для типаNarrowingAttempt(). Тем не менее, в ситуации со сложением двух значений типаbyteвнутриshortконечный результат получился полностью неприемлемым (30000 + 30000 = -5536?).Main()Для построения приложений, в которых потеря данных не допускается, язык C# предлагает ключевые слова
иchecked, которые позволяют гарантировать, что потеря данных не останется необнаруженной.uncheckedИспользование ключевого слова checked
Давайте начнем с выяснения роли ключевого слова
. Предположим, что в классcheckedдобавлен новый метод, который пытается просуммировать две переменные типаProgram, причем каждой из них было присвоено значение, не превышающее допустимый максимум (255). По идее после сложения значений этих двух переменных (с приведением результатаbyteк типуint) должна быть получена точная сумма.bytestatic void ProcessBytes(){byte b1 = 100;byte b2 = 250;byte sum = (byte)Add(b1, b2);// В sum должно содержаться значение 350.// Однако там оказывается значение 94!Console.WriteLine("sum = {0}", sum);}Удивительно, но при просмотре вывода приложения обнаруживается, что в переменной sum содержится значение 94 (а не 350, как ожидалось). Причина проста. Учитывая, что
может хранить только значение в диапазоне от 0 до 255 включительно, вSystem.Byteбудет помещено значение переполнения (350-256 = 94). По умолчанию, если не предпринимаются никакие корректирующие действия, то условия переполнения и потери значимости происходят без выдачи сообщений об ошибках.sum