Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?)
He удается неявно преобразовать тип int в short. Существует явное преобразование (возможно, пропущено приведение)
Проблема в том, что хотя метод Add() способен возвратить значение int, равное 60 000 (которое умещается в допустимый диапазон для System.Int32), это значение не может быть сохранено в переменной short, потому что выходит за пределы диапазона допустимых значений для типа short. Выражаясь формально, среде CoreCLR не удалось применить сужающую операцию. Нетрудно догадаться, что сужающая операция является логической противоположностью расширяющей операции, поскольку предусматривает сохранение большего значения внутри переменной типа данных с меньшим диапазоном допустимых значений.
Важно отметить, что все сужающие преобразования приводят к ошибкам на этапе компиляции, даже когда есть основание полагать, что такое преобразование должно пройти успешно. Например, следующий код также вызовет ошибку при компиляции:
// Снова ошибка на этапе компиляции!
static void NarrowingAttempt()
{
byte myByte = 0;
int myInt = 200;
myByte = myInt;
Console.WriteLine("Value of myByte: {0}", myByte);
}
Здесь значение, содержащееся в переменной типа int(myInt), благополучно умещается в диапазон допустимых значений для типа byte; следовательно, можно было бы ожидать, что сужающая операция не должна привести к ошибке во время выполнения. Однако из-за того, что язык C# создавался с расчетом на безопасность в отношении типов, все-таки будет получена ошибка на этапе компиляции.
Если нужно проинформировать компилятор о том, что вы готовы мириться с возможной потерей данных из-за сужающей операции, тогда потребуется применить явное приведение, используя операцию приведения () языка С#. Взгляните на показанную далее модификацию класса Program:
class 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;
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})
}
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 = -5536
Value of myByte: 200
Как вы только что удостоверились, явное приведение заставляет компилятор применить сужающее преобразование, даже когда оно может вызвать потерю данных. В случае метода NarrowingAttempt() это не было проблемой, т.к. значение 200 умещалось в диапазон допустимых значений для типа byte. Тем не менее, в ситуации со сложением двух значений типа short внутри Main() конечный результат получился полностью неприемлемым (30000 + 30000 = -5536?).
Для построения приложений, в которых потеря данных не допускается, язык C# предлагает ключевые слова checked и unchecked, которые позволяют гарантировать, что потеря данных не останется необнаруженной.
Использование ключевого слова checked
Давайте начнем с выяснения роли ключевого слова checked. Предположим, что в класс Program добавлен новый метод, который пытается просуммировать две переменные типа byte, причем каждой из них было присвоено значение, не превышающее допустимый максимум (255). По идее после сложения значений этих двух переменных (с приведением результата int к типу byte) должна быть получена точная сумма.
static 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, как ожидалось). Причина проста. Учитывая, что System.Byte может хранить только значение в диапазоне от 0 до 255 включительно, в sum будет помещено значение переполнения (350-256 = 94). По умолчанию, если не предпринимаются никакие корректирующие действия, то условия переполнения и потери значимости происходят без выдачи сообщений об ошибках.