
Объектно-ориентированное программирование.-6
.pdf
|
White, AllowTrailingWhite и AllowHexSpecifier |
|
|
Number (0x006f) |
Используется комбинация стилей AllowLeading- |
|
White, AllowTrailingWhite, AllowLeadingSign, Allow- |
|
TrailingSign, AllowDecimalPoint и AllowThousands |
|
|
Float (0x00a7) |
Используется комбинация стилей AllowLeading- |
|
White, AllowTrailingWhite, AllowLeadingSign, Allow- |
|
Exponent и AllowDecimalPoint |
|
|
Currency (0x017f) |
Используется комбинация всех стилей, за исключе- |
|
нием AllowExponent и AllowHexSpecifier |
|
|
Any (0x01ff) |
Используется комбинация всех стилей, за исключе- |
|
нием AllowHexSpecifier |
|
|
Пример:
string str; int v1; double v2;
NumberFormatInfo nfi = new NumberFormatInfo();
CultureInfo ru = CultureInfo.CreateSpecificCulture("ru-RU"); CultureInfo us = CultureInfo.CreateSpecificCulture("en-US");
str = "A";
v1 = int.Parse(str, NumberStyles.HexNumber); Console.WriteLine("'0x{0}' = '{1}'", str, v1);
str = " |
-45 |
"; |
|
v1 = int.Parse(str, |
NumberStyles.AllowLeadingSign | |
NumberStyles.AllowLeadingWhite |
NumberStyles.AllowTrailingWhite); Console.WriteLine("'{0}' = '{1}'", str, v1); str = " (37) ";
v1 = int.Parse(str, NumberStyles.AllowParentheses | NumberStyles.AllowLeadingSign | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite);
Console.WriteLine("'{0}' = '{1}'", str, v1); str = "123,456";
v1 = int.Parse(str, NumberStyles.AllowThousands, us); Console.WriteLine("'{0}' = '{1}' ({2})", str, v1, us.Name); v2 = double.Parse(str, NumberStyles.AllowDecimalPoint, ru); Console.WriteLine("'{0}' = '{1}' ({2})", str, v2, ru.Name);
if (int.TryParse(str, NumberStyles.AllowThousands, ru, out v1))
{
Console.WriteLine("'{0}' = '{1}'", str, v1);
}
else
{
Console.WriteLine("'{0}': не удалось преобразовать в тип int
({1})", str, ru.Name);
}
Вывод на консоль:
161

'0xA' = '10'
'-45 ' = '-45'
'(37) ' = '-37'
'123,456' = '123456' (en-US) '123,456' = '123,456' (ru-RU)
'123,456': не удалось преобразовать в тип int (ru-RU)
3.2.3.2. Разбор строк со значениями bool и char
Для этих типов данных предусмотрены только два метода разбора:
static <тип> Parse(string value);
static bool TryParse(string value, out <тип> result);
Для логического типа разбор будет успешен, если строка содержит значение Boolean.FalseString или Boolean.TrueString (регистр символов не важен). Для символьного типа – если строка содержит один символ Unicode.
Пример:
bool v3; char v4;
str = "true";
v3 = bool.Parse(str); Console.WriteLine("'{0}' = '{1}'", str, v3); str = "истина";
if (bool.TryParse(str, out v3))
{
Console.WriteLine("'{0}' = '{1}'", str, v3);
}
else
{
Console.WriteLine("'{0}': не удалось преобразовать в тип bool",
str);
}
str = "Ё";
v4 = char.Parse(str); Console.WriteLine("'{0}' = '{1}'", str, v4); str = "!!!";
if (char.TryParse(str, out v4))
{
Console.WriteLine("'{0}' = '{1}'", str, v4);
}
else
{
Console.WriteLine("'{0}': не удалось преобразовать в тип char",
str);
}
Вывод на консоль:
'true' = 'True'
'истина': не удалось преобразовать в тип bool
162

'Ё' = 'Ё'
'!!!': не удалось преобразовать в тип char
3.2.3.3.Разбор строк со значениями перечисляемого типа
Вклассе System.Enum есть два варианта метода Parse:
static object Parse(Type enumType, string value);
static object Parse(Type enumType, string value, bool ignoreCase);
Метод TryParse не предусмотрен. Параметр ignoreCase позволяет игнорировать регистр символов. Если искомая символическая константа в указанном перечислении не найдена, генерируется исключительная ситуация
System.ArgumentException.
Пример:
DayOfWeek v5;
Console.WriteLine("Разбор перечисляемого типа"); str = "Friday";
v5 = (DayOfWeek)Enum.Parse(typeof(DayOfWeek), str); Console.WriteLine("'{0}' = '{1}'", str, v5);
str = "MonDAY";
v5 = (DayOfWeek)Enum.Parse(v5.GetType(), str, true); Console.WriteLine("'{0}' = '{1}'", str, v5);
str = "zzz";
try
{
v5 = (DayOfWeek)Enum.Parse(v5.GetType(), str, true); Console.WriteLine("'{0}' = '{1}'", str, v5);
}
catch (ArgumentException e)
{
Console.WriteLine(e);
}
Вывод на консоль:
'Friday' = 'Friday' 'MonDAY' = 'Monday'
System.ArgumentException: Запрошенное значение "zzz" не найдено
3.2.3.4. Разбор строк с датой и временем
Для разбора даты и времени предусмотрены следующие методы:
static DateTime Parse(string s);
static DateTime Parse(string s, IFormatProvider provider);
static DateTime Parse(string s, IFormatProvider provider, DateTimeStyles styles);
static DateTime ParseExact(string s, string format, IFormatProvider provider);
static DateTime ParseExact(string s, string format, IFormatProvider
163

provider, DateTimeStyles style);
static DateTime ParseExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style);
static bool TryParse(string s, out DateTime result);
static bool TryParse(string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result);
static bool TryParseExact(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result);
static bool TryParseExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result);
Методы Parse пытаются преобразовать строку к значению даты и времени, основываясь на указанной реализации интерфейса IFormatProvider и дополнительных опций, задаваемых перечислением DateTimeStyles (табл. 3.15).
|
Табл. 3.15 – Константы перечисления DateTimeStyles |
|
|
|
|
Константа |
|
Описание |
|
|
|
None (0x0000) |
|
Используются параметры форматирования по |
|
|
умолчанию |
|
|
|
AllowLeadingWhite |
|
Начальные знаки-разделители не следует учиты- |
(0x0001) |
|
вать при разборе |
|
|
|
|
|
|
AllowTrailingWhite |
|
Конечные знаки-разделители не следует учиты- |
(0x0002) |
|
вать при разборе |
|
|
|
|
|
|
AllowInnerWhite |
|
Лишние знаки-разделители в середине строки не |
(0x0004) |
|
следует учитывать при разборе |
|
|
|
|
|
|
AllowWhiteSpaces |
|
Лишние знаки-разделители в любом месте строки |
(0x0007) |
|
не следует учитывать при разборе (комбинация |
|
|
|
|
|
AllowLeadingWhite, AllowTrailingWhite и Allow- |
|
|
InnerWhite) |
|
|
|
NoCurrentDateDefault |
|
Если в разбираемой строке содержится только |
(0x0008) |
|
время и отсутствует дата, подразумевается дата |
|
|
|
|
|
1.1.1. Если это значение не используется, подра- |
|
|
зумевается текущая дата |
|
|
|
AdjustToUniversal |
|
Дата и время возвращаются в формате универ- |
(0x0010) |
|
сального времени (UTC) |
|
|
|
|
|
|
AssumeLocal (0x0020) |
|
Если часовой пояс не указан в строке разбора, |
|
|
подразумевается, что используется локальное |
|
|
время |
|
|
|
AssumeUniversal |
|
Если часовой пояс не указан в строке разбора, |
|
|
|
|
164 |

(0x0040) |
подразумевается, что используется формат UTC |
|
|
RoundtripKind |
Поле даты DateTimeKind сохраняется при преоб- |
(0x0080) |
разовании в строку с помощью стандартного |
|
|
|
описателя формата «o» или «r» и преобразования |
|
строки обратно |
|
|
Методы ParseExact делают то же самое, но требуют точного совпадения строки даты и времени с указанным форматом или массивом форматов.
Методы TryParse и TryParseExact отличаются от Parse и ParseExact тем же – при ошибке преобразования не выдают исключительную ситуацию, а возвращают false.
Пример:
DateTime v6;
Console.WriteLine("Разбор даты и времени:"); str = " Friday, August 20, 2010 18:30 ";
v6 = DateTime.Parse(str); Console.WriteLine("'{0}' = '{1}'", str, v6);
try
{
v6 = DateTime.ParseExact(str, "D", us); Console.WriteLine("'{0}' = '{1}'", str, v6);
}
catch (FormatException)
{
Console.WriteLine("'{0}' не является датой в формате '{1}'", str, us.DateTimeFormat.LongDatePattern);
}
str = " Friday, August 20, 2010 ";
v6 = DateTime.ParseExact(str, "D", us, DateTimeStyles.AllowWhiteSpaces); Console.WriteLine("'{0}' = '{1}'", str, v6);
Вывод на консоль:
'Friday, August 20, 2010 18:30 ' = '20.08.2010 18:30:00'
'Friday, August 20, 2010 18:30 ' не является датой в формате 'dddd, MMMM dd, yyyy'
'Friday, August 20, 2010 ' = '20.08.2010 0:00:00'
Во втором случае преобразование вызвало ошибку потому, что в строке с датой были лишние пробелы, и время в формате «D» не должно содержаться. В третьем случае время из строки мы убрали, а лишние пробелы игнорируются, т.к. указан флаг AllowWhiteSpaces.
165

3.2.4. Ввод с консоли
Для чтения данных с консоли в классе System.Console предназначены следующие методы:
static int Read();
static string ReadLine();
static ConsoleKeyInfo ReadKey();
static ConsoleKeyInfo ReadKey(bool intercept);
Пример: Samples\3.2\3_2_4_read.
3.2.4.1. Метод Read
Метод Read читает один символ из потока ввода. Он возвращает значение типа int, равное коду прочитанного символа, либо –1, если в буфере ввода нет символов. Может показаться, что этот метод похож на функцию getch из консольной библиотеки языка C++ (conio.h). Однако, это не так. Когда выполнение программы доходит до вызова метода Read, пользователь может ввести не один символ, а сразу целую строку, завершив ее ввод нажатием клавиши «Enter». Метод Read вернет первый символ введенной строки, следующий вызов данного метода вернет второй символ, и т.д.
Что интересно, в режиме чтения действуют некоторые функции командной строки Windows. Так, нажатие клавиш «↑» и «↓» будет помещать в позицию ввода строки, расположенные в истории ввода ранее или позже, и т.д.
Чтобы метод Read вернул –1, необходимо на консоли ввести символ окончания ввода (комбинация клавиш Ctrl+Z или F6, затем Enter).
Приведем пример программы:
int i; string str; char c;
Console.WriteLine("Вводите любые строки текста.");
Console.WriteLine("Можно использовать клавиши 'Вверх'");
Console.WriteLine("и 'Вниз' для перемещения по истории");
Console.WriteLine("ввода. Для выхода из режима ввода");
Console.WriteLine("нажмите Ctrl+Z или F6, затем Enter");
do
{
i = Console.Read();
if (i != -1)
{
166

c = Convert.ToChar(i);
Console.Write("Символ с кодом U+{0:X4}", i);
if (Char.IsControl(c)) Console.WriteLine(" [управляющий]"); else Console.WriteLine(" = '{1}'", i, c);
}
} while (i != -1);
Результаты работы программы:
привет!
Символ с кодом U+043F = 'п' Символ с кодом U+0440 = 'р' Символ с кодом U+0438 = 'и' Символ с кодом U+0432 = 'в' Символ с кодом U+0435 = 'е' Символ с кодом U+0442 = 'т' Символ с кодом U+0021 = '!'
Символ с кодом U+000D [управляющий] Символ с кодом U+000A [управляющий]
^Z
В данном примере сначала была введена строка «привет!». В буфер клавиатуры попали символы этой строки, а также символы «\r» (0x0d) и «\n» (0x0a), которыми завершился ее ввод. Затем информация об этих символах была выведена на консоль. При следующем запросе на ввод строки была нажата комбинация клавиш Ctrl+Z и Enter, завершившая ввод.
3.2.4.2. Метод ReadLine
Метод ReadLine читает из потока ввода строку текста, которая завершается символом перевода строки и/или возврата каретки («\r» и/или «\n»). Метод возвращает объект типа string или null, если ввод осуществить не удалось (т.е. если в буфере клавиатуры или другого потока ввода был символ окончания ввода):
Console.WriteLine("Вводите любые строки текста.");
Console.WriteLine("Для выхода из режима ввода нажмите");
Console.WriteLine("Ctrl+Z или F6, затем Enter");
do
{
str = Console.ReadLine(); if (str != null)
{
Console.WriteLine("Введена строка '{0}'", str);
}
} while (str != null);
Результаты работы программы:
привет!
Введена строка 'привет!'
^Z
167
После считывания строки со значениями можно осуществлять ее разбор различными модификациями метода Parse.
3.2.4.3. Метод ReadKey
Метод ReadKey, как и метод Read, позволяет прочитать из буфера клавиатуры или потока ввода один символ, но работает уже как аналог функции getch. Т.е. можно считывать не только обычные символы, но и сочетания клавиш.
Метод имеет две разновидности. Вторая позволяет управлять отображением введенного символа (если параметр intercept равен true, символ не отображается, иначе отображается на консоли). Первый вариант метода всегда отображает введенный символ.
Информация о нажатых клавишах возвращается в виде экземпляров структуры ConsoleKeyInfo (табл. 3.16).
Табл. 3.16 – Основные члены структуры ConsoleKeyInfo
Член |
|
Описание |
|
|
|
Конструкторы |
||
|
|
|
ConsoleKeyInfo(char keyChar, |
|
Инициализирует новый экземпляр |
ConsoleKey key, bool shift, |
|
структуры ConsoleKeyInfo с использо- |
bool alt, bool control) |
|
|
|
ванием заданного символа, клавиши |
|
|
|
|
|
|
консоли и управляющих клавиш |
|
|
|
Операторы |
||
|
|
|
static bool operator == |
|
Указывает, равны ли заданные объекты |
(ConsoleKeyInfo a, |
|
|
ConsoleKeyInfo b) |
|
|
|
|
|
static bool operator != |
|
Указывает, являются ли заданные объ- |
(ConsoleKeyInfo a, |
|
екты неравными |
|
|
|
ConsoleKeyInfo b) |
|
|
|
|
|
|
Свойства |
|
|
|
|
ConsoleKey Key |
|
Возвращает клавишу консоли, пред- |
|
|
ставленную текущим объектом |
|
|
|
char KeyChar |
|
Возвращает символ Unicode, представ- |
|
|
ленный текущим объектом |
|
|
|
ConsoleModifiers Modifiers |
|
Возвращает состояние управляющих |
|
|
клавиши (Shift, Alt или Ctrl) – нажаты |
|
|
|
|
168 |

они или нет
Перечисление ConsoleModifiers содержит именованные константы Alt, Shift и Control. Левые и правые управляющие клавиши не различаются. Свойство KeyChar позволяет получить доступ к коду нажатой клавиши, если это обычный символ. Свойство Key – если была нажата любая клавиша клавиатуры. Перечисление ConsoleKey содержит именованные константы для каждой клавиши. Их несколько десятков, полный список можно посмотреть в библиотеке MSDN.
Как мы помним, в библиотеках языка C++ также была функция kbhit(), позволяющая узнать, есть ли во входном потоке данные о нажатых клавишах. В языке C# ее аналогом является следующее свойство класса Console:
static bool KeyAvailable;
Пример:
Console.WriteLine("Нажимайте любые комбинации клавиш,");
Console.WriteLine("чтобы увидеть их интерпретацию.);
Console.WriteLine("Выход по Ctrl+Пробел");
ConsoleKeyInfo exit = new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, true);
ConsoleKeyInfo key;
do
{
key = Console.ReadKey(true);
Console.Write("Вы нажали ");
if (((int)key.Modifiers & (int)ConsoleModifiers.Alt) != 0) Console.Write("Alt+");
if (((int)key.Modifiers & (int)ConsoleModifiers.Shift) != 0) Console.Write("Shift+");
if (((int)key.Modifiers & (int) ConsoleModifiers.Control) != 0) Console.Write("Ctrl+");
Console.WriteLine(Enum.GetName(typeof(ConsoleKey), key.Key)); } while (key != exit);
Результаты работы программы:
Вы нажали Shift+Ctrl+F
Вы нажали Alt+F5 Вы нажали Shift+Z Вы нажали R
Вы нажали Shift+Ctrl+Insert Вы нажали Ctrl+Spacebar
Результаты работы зависят от того, какие клавиши будут нажаты.
169
§3.3. Вычисление выражений
Вданном параграфе мы рассмотрим вычисление выражений – это одна из трех основ структурного программирования. Две другие – организация в программе ветвлений и циклов, рассмотрены в следующем параграфе. Вычисление выражений состоит в применении операций языка по отношению к данным (аргументам операций).
При вычислении выражений используются операторы выражений. Также существуют операторы языка C#, рассмотренные в § 3.4. В дальнейшем мы как операторы выражений, так и операторы языка будем называть просто операторами. О том, какие именно операторы имеются в виду, будет ясно из контекста.
Итак, оператор выражения – это символ, указывающий, какую операцию необходимо выполнить над одним или несколькими аргументами. При выполнении оператора получается результат. Синтаксис применения операторов несколько отличен от вызова методов, поэтому необходимо знать формат выражений, содержащих операторы языка C#. Как и в большинстве других языков, семантика операторов в C# соответствует правилам и нотациям, знакомым нам из математики и из языка C++.
3.3.1.Набор операторов языка C#
Стандартные операторы, определенные в языке C#, перечислены в табл. 3.17.
|
Табл. 3.17 – Операторы языка C# (по категориям) |
|
|
|
|
Категория |
|
Операторы |
|
|
|
Арифметические |
|
+ – * / % |
|
|
|
Инкремента и декремента |
|
++ –– |
|
|
|
Логические |
|
&& || ! true false |
|
|
|
Побитовые |
|
& | ^ ~ << >> |
|
|
|
Сравнения |
|
== != < > <= >= |
|
|
|
Присваивания |
|
= *= /= %= += –= <<= >>= &= ^= |= |
|
|
|
Доступа |
|
. :: |
|
|
|
Индексирования |
|
[] |
|
|
|
Преобразования типа |
|
() as |
|
|
|
|
170 |