Выражения и операции
Класс Convert и его методы
Для преобразований внутри арифметического типа можно использовать кастинг - приведение типа. Для преобразований строкового типа в скалярный тип можно применять метод Parse, а в обратную сторону - метод ToString.
Во всех ситуациях, когда требуется выполнить преобразование из одного базового встроенного типа в другой базовый тип, можно использовать методы класса Convert библиотеки FCL, встроенного в пространство имен System - универсального класса, статические методы которого специально спроектированы для выполнения преобразований.
Среди других методов класса Convert отмечу общий статический метод ChangeType, позволяющий преобразование объекта к некоторому заданному типу. Отмечу также возможность преобразования к системному типу DateTime, который хотя и не является базисным типом языка C#, но допустим в программах, как и любой другой системный тип.
Кроме методов, задающих преобразования типов, в классе Convert имеются и другие методы, например, задающие преобразования символов Unicode в однобайтную кодировку ASCII, преобразования, связанные с массивами, и другие методы. Подробности можно посмотреть в справочной системе.
Методы класса Convert поддерживают общий способ выполнения преобразований между типами. Класс Convert содержит 15 статических методов вида To<Type> (ToBoolean(),…ToUInt64()), где Type может принимать значения от Boolean до UInt64 для всех встроенных типов, перечисленных в таблице 3.1. Единственным исключением является тип object - метода ToObject нет по понятным причинам, поскольку для всех типов существует неявное преобразование к типу object. Каждый из этих 15 методов перегружен, и его аргумент x может принадлежать к любому из упомянутых типов. С учетом перегрузки с помощью методов этого класса можно осуществить любое из возможных преобразований одного типа в другой. Все методы осуществляют проверяемые преобразования и включают исключительную ситуацию всякий раз, когда преобразование осуществить невозможно или при выполнении преобразования происходит потеря точности. Приведу пример:
/// <summary> /// Тестирование методов класса Convert /// </summary> public void ConvertTest() { string s; byte b; int n; double x; bool flag; char sym; DateTime dt; sym = '7'; s = Convert.ToString(sym); x = Convert.ToDouble(s); n = Convert.ToInt32(x); b = Convert.ToByte(n); flag = Convert.ToBoolean(b); x = Convert.ToDouble(flag); s = Convert.ToString(flag); // sym = Convert.ToChar(flag); s = "300"; n = Convert.ToInt32(s); //b = Convert.ToByte(s); s ="14.09"; //flag = Convert.ToBoolean(s); //x = Convert.ToDouble(s); s = "14.09.2008"; dt = Convert.ToDateTime(s); }
Этот пример демонстрирует различные преобразования между типами. Все эти преобразования опасные, выполняются явно с использованием методов класса Convert. Вначале данные символьного типа преобразуются в строку. Затем эти данные преобразуются в вещественный тип, далее проводятся преобразования внутри арифметического типа с понижением типа от double до byte. Завершающим пример преобразованием является преобразование данных строкового типа к типу DateTime.
Опасные преобразования одного типа к другому могут успешно выполняться над некоторыми данными и приводить к ошибке с другими данными. В нашем примере закомментированы операторы, приводящие к ошибкам в период выполнения. Первая ошибка возникает при попытке преобразовать данные булевского типа к символьному типу, поскольку отсутствует преобразование, которое значение true преобразовывало бы в некоторый символ (например Т). Заметьте, что в предыдущих операторах эти же данные успешно были приведены к строковому и арифметическому типу. Следующая ошибка возникает при попытке преобразовать строку со значением 300 к типу byte. Соответствующий метод распознает, что значение, записанное в строке, слишком велико для типа, представляющего цель преобразования. Еще одна ошибка возникает при попытке привести к булевскому типу строку, отличную от записи булевских констант true и false. Последняя ошибка в данном примере довольно часто встречается на практике. Она связана с тем, что ошибочно использована точка вместо запятой для отделения дробной части числа.
Какие выводы следует сделать? Опасные преобразования, выполняемые методами класса Convert, действительно опасны. По этой причине их всегда следует помещать в охраняемый блок и создавать блоки, обрабатывающие возможную исключительную ситуацию. Обработчик ситуации должен решать две важные задачи. Первая из них - информационная, он должен выдать достаточно подробную информацию с описанием возникшей ошибки. Вторая задача не менее важна. Обработчик должен попытаться исправить ситуацию, чтобы программа могла продолжить нормальное выполнение. Он должен, например, позволить пользователю повторить ввод некорректно заданных данных, вызвать для корректировки ситуации дополнительный модуль. В каждом конкретном случае меры для восстановления работы могут быть разными.
Класс Console и его методы
В заключение этой лекции рассмотрим работу с методами класса Console. Хотя этот класс не связан непосредственно с выражениями - основной темой данной лекции, но он имеет прямое отношение к преобразованиям типов данных и вводу-выводу данных. Без использования методов этого класса в консольных проектах не обойтись.
Класс Console используется в консольных проектах, позволяя вводить исходные данные с консоли и выводить результаты на консоль. По умолчанию при вводе с консоли данные вводятся с клавиатуры и отображаются на дисплее, при выводе на консоль - данные отображаются на экране дисплея. У класса Console десятки свойств и методов. Ограничимся рассмотрением основных методов, используемых при вводе и выводе.
4
Методы Read и ReadLine позволяют читать с консоли текст, отображаемый на экране дисплея компьютера. Методы не имеют входных аргументов. Оператор Read читает по одному символу из входной строки и возвращает в качестве результата код прочитанного символа, имеющий тип int. Посимвольный ввод применяется довольно редко. Вот некоторый пример возможного применения чтения текста с использованием оператора Read.
public void ReadTest() { Console.WriteLine("Введите текст." + "Признаком конца текста являются два подряд идущих !! "); char ch = Convert.ToChar(Console.Read()); char next =' '; string result = ""; bool finish = false; do { result += ch.ToString(); next = Convert.ToChar(Console.Read()); if (ch != '!') ch = next; else { if (next == '!') finish = true; else ch = next; } }while (!finish); Console.ReadLine(); Console.WriteLine(result); }
В этом примере текст, введенный пользователем, читается посимвольно до тех пор, пока не встретится специальный признак конца чтения. В данном случае таким признаком является два подряд идущих восклицательных знака.
Вызов метода ReadLine, завершающий процедуру, позволяет "дочитать" оставшиеся символы отображаемой строки текста и перевести курсор ввода на новую строку. Такие символы всегда будут, поскольку всякая строка завершается символом конца строки, не прочитанным методом Read. На рис. 3.8 показаны результаты работы при вызове процедуры ReadTest.
Основным методом, используемым для чтения данных с консоли, является метод ReadLine. Он читает с консоли строку текста, завершаемую признаком конца строки. Эта строка и является результатом, возвращаемым методом ReadLine. Примеров применения этого метода было уже предостаточно.
Вывод данных на консоль. Методы Write и WriteLine
Методы Write и WriteLine позволяют выводить текст на консоль. Метод Write выводит текст на консоль и на этом завершает свою работу. Всякий последующий вывод на консоль продолжится с того места, на котором завершил свою работу метод Write. В отличие от метода Write метод WriteLine выводит текст на консоль, после чего осуществляет переход на новую строку.
Выводимый текст задается аргументами методов. С аргументами методов стоит разобраться подробнее, поскольку у этих методов может быть сколь угодно много аргументов. В простейшем случае у методов один аргумент типа string, именно эта строка выводится на консоль. Но строка, задающая первый аргумент, может быть форматированной, и тогда после первого аргумента появляется дополнительный список аргументов, каждый из которых может иметь свой тип данных.
Строка называется форматированной, если она содержит форматы. Формат, включаемый в строку, задается последовательностью символов, заключенной в фигурные скобки. Каждый формат задает место подстановки. В процессе форматизации в строку вместо формата подставляется некоторая другая строка. Форматы могут быть разными, и подробнее о них поговорим при описании работы со строками. В простейшем случае задания формата в фигурных скобках стоит целое число k. Это число определяет порядковый номер аргумента из дополнительного списка, при этом нумерация аргументов списка начинается с нуля. Аргумент с номером k из дополнительного списка преобразуется в строку и подставляется вместо соответствующего формата. Преобразование аргумента в строку происходит автоматически, используя метод ToString, который имеют все типы данных.
Рассмотрим применение методов Write, WrteLine, ReadLine на примере ввода и вывода с консоли квадратной матрицы:
/// <summary> /// Ввод-вывод с консоли квадратной матрицы /// </summary> public void InOutMatrix() { int n; Console.WriteLine("Ввод квадратной матрицы A размерности n"); Console.WriteLine("Введите целое - n"); n = Convert.ToInt32(Console.ReadLine()); double[,] A = new double[n,n]; for(int i = 0; i<n; i++) for (int j = 0; j < n; j++) { Console.WriteLine("Введите A[{0}],[{1}]", i, j); A[i, j] = Convert.ToDouble(Console.ReadLine()); } Console.WriteLine("Вывод матрицы A"); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) Console.Write("A[{0}],[{1}] = {2} ", i, j, A[i, j]); Console.WriteLine(); } }
На рис. 3.9 показаны результаты вызова этого метода.