Вы, несомненно, прекрасно знаете, что любой числовой тип данных имеет свои строго заданные верхний и нижний пределы (значения которых можно выяснить программными средствами с помощью свойств MaxValue и MinValue). При выполнении арифметических операций с конкретным типом вполне возможно случайное
Для примера предположим, что мы создали два экземпляра типа System.Byte (тип byte в C#), присвоив им значения, не превышающие максимального (255). При сложении значений этих типов (с условием преобразования результата в тип byte) хотелось бы предполагать, что результат будет точной суммой соответствующих членов.
namespace CheckedUnchecked {
class Program {
static void Main(string[] args) {
// Переполнение для System.Byte.
Console.WriteLine("Макс, значение для byte равно {0}", byte.MaxValue);
Console.WriteLine("Мин. значение для byte равно {0}", byte.MinValue);
byte b1 = 100;
byte b2 = 250;
byte sum = (byte)(b1 + b2);
// Значением sum должно быть 350, но.…
Console.WriteLine("sum = {0}", sum);
Console.ReadLine;
}
}
}
Вывод этого приложения покажет, что sum содержит значение 94 (а не ожидаемое 350). Причина очень проста. Поскольку System.Byte может содержать только значения, находящиеся между 0 и 255 (что в итоге составляет 256 значений), sum будет содержать значение переполнения (350 – 256 = 94). Как видите, в отсутствие специальной коррекции переполнение происходит без генерирования исключений. Иногда скрытое переполнение не создает никаких проблем. В других случаях соответствующая потеря данных может быть совершенно неприемлемой.
Для обработки переполнений или потери значимости в приложении имеются две возможности. Первой возможностью является использование программистского опыта и квалификации с тем, чтобы обработать все условия переполнения вручную. Предполагая, что вы можете найти все условия переполнения в программе, можно было бы решить проблему, связанную с переполнением в предыдущем программном коде, как показано ниже.
// Использование int для sum, чтобы не допустить переполнения.
byte b1 = 100;
byte b2 = 250;
int
Конечно, проблемой этого подхода является то, что вы – человек, а значит, при всех ваших усилиях, могут остаться ошибки, ускользнувшие от вашего взгляда. Поэтому в C# предлагается ключевое слово checked. При помещении оператора (или блока операторов) в рамки контекста ключевого слова checked компилятор C# генерирует специальные CIL-инструкщии, с помощью которых проверяются условия переполнения, возможные при выполнении сложения, умножение, вычитания или деления числовых типов данных. Если происходит переполнение, среда выполнения генерирует тип System.OverflowException. Рассмотрите следующую модификацию программы.
class Program {
static void Main(string[] args) {
// Переполнение для System.Byte.
Console.WriteLine("Макс. значение для byte равно {0}.", byte.MaxValue);
byte b1 = 100;
byte b2 = 250;
try {
byte sum = checked
Console.WriteLine("sum = {0}", sum);
} catch (OverflowException e) { Console.WriteLine(e.Message); }
}
}
Здесь оператор сложения b1 и b2 помещается в контекст ключевого слова checked. Если вы хотите, чтобы проверка переполнения происходила для блока программного кода, можно взаимодействовать с ключевым словом checked так, как показано ниже.
try {
checked
byte sum = (byte)(b1 + b2);
Console.WritaLine(sum = {0}", sum);
}
} catch (OverflowException e) {
Console.WriteLine(e.Message);
}