// Продемонстрировать применение ключевых слов checked и unchecked.using System;
class CheckedDemo { static void Main() { byte a, b; byte result; a = 127; b = 127; try { result = unchecked((byte)(a b)); Console.WriteLine("Непроверенный на переполнение результат: " + result); result = checked((byte)(a b)); // эта операция приводит к // исключительной ситуации Console.WriteLine("Проверенный на переполнение результат: " + result); //не подлежит выполнению } catch (OverflowException exc) { Console.WriteLine(exc); } }}При выполнении этой программы получается следующий результат.
Непроверенный на переполнение результат: 1System.OverflowException: Переполнение в результатевыполнения арифметической операции. в CheckedDemo.Main() в <имя_файла>:строка 20Как видите, результат вычисления непроверяемого выражения был усечен. А вычисление проверяемого выражения привело к исключительной ситуации.В представленном выше примере программы было продемонстрировано применение ключевых слов checked и unchecked в одном выражении. А в следующем примере программы показывается, каким образом проверяется и не проверяется на переполнение целый блок операторов.
// Продемонстрировать применение ключевых слов checked// и unchecked в блоке операторов.using System;
class CheckedBlocks { static void Main() { byte a, b; byte result; a = 127; b = 127; try { unchecked { a = 127; b = 127; result = unchecked((byte)(a * b)); Console.WriteLine("Непроверенный на переполнение результат: " + result); а = 125; b = 5; result = unchecked((byte)(a * b)); Console.WriteLine("Непроверенный на переполнение результат: " + result); } checked { a = 2; b = 7; result = checked((byte)(a * b)); // верно Console.WriteLine("Проверенный на переполнение результат: " + result); а = 127; b = 127; result = checked((byte)(a * b)); // эта операция приводит к // исключительной ситуации Console.WriteLine("Проверенный на переполнение результат: " + result); // не подлежит выполнению } } catch (OverflowException exc) { Console.WriteLine(exc); }}
}Результат выполнения этой программы приведен ниже.
Непроверенный на переполнение результат: 1Непроверенный на переполнение результат: 113Проверенный на переполнение результат: 14System.OverflowException: Переполнение в результатевыполнения арифметической операции. в CheckedDemo.Main() в <имя_файма>:строка 41```Как видите, результаты выполнения непроверяемого на переполнение блока операторов были усечены. Когда же в проверяемом блоке операторов произошло переполнение, то возникла исключительная ситуация.
Потребность в применении ключевого слова checked или unchecked может возникнуть, в частности, потому, что по умолчанию проверяемое или непроверяемое состояние переполнения определяется путем установки соответствующего параметракомпилятора и настройки самой среды выполнения. Поэтому в некоторых программах состояние переполнения лучше проверять явным образом.
ГЛАВА 14. Применение средств ввода-вывода
В примерах программ, приводившихся в предыдущих главах, уже применялись отдельные части системы ввода-вывода в С#, например метод Console.WriteLine(), но делалось это без каких-либо формальныхпояснений. Система ввода-вывода основана в C# на иерархии классов, поэтому ее функции и особенности нельзябыло представлять до тех пор, пока не были рассмотреныклассы, наследование и исключения. А теперь настал череди для ввода-вывода. В C# применяется система ввода-выводаи классы, определенные в среде .NET Framework, и поэтомурассмотрение ввода-вывода в этом языке относится ко всейсистеме ввода-вывода среды .NET в целом.
В этой главе речь пойдет о средствах консольного и файлового ввода-вывода. Следует, однако, сразу же предупредить, что система ввода-вывода в C# довольно обширна. Поэтому в этой главе рассматриваются лишь самые важныеи наиболее часто используемые ее средства.Организация системы ввода-вывода в C# на потоках
Ввод-вывод в программах на C# осуществляется посредством потоков. Поток — это некая абстракция производства или потребления информации. С физическим устройством поток связывает система ввода-вывода. Все потокидействуют одинаково — даже если они связаны с разнымифизическими устройствами. Поэтому классы и методыввода-вывода могут применяться к самым разным типамустройств. Например, методами вывода на консоль можнопользоваться и для вывода в файл на диске.Байтовые и символьные потоки
На самом низком уровне ввод-вывод в С# осуществляется байтами. И делается этопотому, что многие устройства ориентированы на операции ввода-вывода отдельнымибайтами. Но человеку больше свойственно общаться символами. Напомним, что в C#тип char является 16-разрядным, а тип byte — 8-разрядным. Так, если в целях ввода-вывода используется набор символов в коде ASCII, то для преобразования типа charв тип byte достаточно отбросить старший байт значения типа char. Но это не годится для набора символов в уникоде (Unicode), где символы требуется представлять двумя,а то и больше байтами. Следовательно, байтовые потоки не совсем подходят для организации ввода-вывода отдельными символами. С целью разрешить это затруднениев среде .NET Framework определено несколько классов, выполняющих превращениебайтового потока в символьный с автоматическим преобразованием типа byte в типchar и обратно.Встроенные потоки
Для всех программ, в которых используется пространство имен System, доступнывстроенные потоки, открывающиеся с помощью свойств Console.In, Console.Outи Console.Error. В частности, свойство Console.Out связано со стандартным потоком вывода. По умолчанию это поток вывода на консоль. Так, если вызывается методConsole.WriteLine(), информация автоматически передается свойству Console.Out. Свойство Console.In связано со стандартным потоком ввода, который по умолчанию осуществляется с клавиатуры. А свойство Console.Error связано со стандартным потоком сообщений об ошибках, которые по умолчанию также выводятсяна консоль. Но эти потоки могут быть переадресованы на любое другое совместимоеустройство ввода-вывода. Стандартные потоки являются символьными. Поэтому в этипотоки выводятся и вводятся из них символы.Классы потоков
В среде .NET Framework определены классы как для байтовых, так и для символьных потоков. Но на самом деле классы символьных потоков служат лишь оболочкамидля превращения заключенного в них байтового потока в символьный, автоматическивыполняя любые требующиеся преобразования типов данных. Следовательно, символьные потоки основываются на байтовых, хотя они и разделены логически.Основные классы потоков определены в пространстве имен System.IO. Для тогочтобы воспользоваться этими классами, как правило, достаточно ввести приведенныйниже оператор в самом начале программы.using System.IO;
Пространство имен System.IO не указывается для консольного ввода-вывода потому, что для него определен класс Console в пространстве имен System.Класс Stream
Основным для потоков является класс System.IO.Stream. Он представляет байтовый поток и является базовым для всех остальных классов потоков. Кроме того, онявляется абстрактным классом, а это означает, что получить экземпляр объекта классаStream нельзя. В классе Stream определяется ряд операций со стандартными потоками, представленных соответствующими методами. В табл. 14.1 перечислен ряд наиболее часто используемых методов, определенных в классе Stream.
Таблица 14.1. Некоторые методы, определенные в классе StreamМетодОписаниеvoid Close()Закрывает потокvoid Flush()Выводит содержимое потока на физическое устройствоint ReadByte()Возвращает целочисленное представление следующего байта, доступного для ввода из потока. При обнаружении конца файла возвращает значение -1int Read(byte[] buffer, int offset, int count)Делает попытку ввести count байтов в массив buffer, начиная с элемента buffer[offset]. Возвращает количество успешно введенных байтовlong Seek(long offset, SeekOrigin origin)Устанавливает текущее положение в потоке по указанному смещению offset относительно заданного начала отсчета origin. Возвращает новое положение в потокеvoid WriteByte(byte value)Выводит один байт в поток выводаvoid Write(byte[]buffer, int offset, int count)Выводит подмножество count байтов из массива buffer, начиная с элемента buffer[offset]. Возвращает количество выведенных байтов