Автор: Мартыненко Т.В. Турупалов В.В. Андриевская Н.К.
Теги: языки программирования дисплейный интерфейс программирование графика информационные технологии учебное пособие язык программирования c#
ISBN: 978-5-9729-1225-4
Год: 2023
Т. В. Мартыненко
В. В. Турупалов
Н. К. Андриевская
ОСНОВЫ
ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ
В СРЕДЕ VISUAL STUDIO НА БАЗЕ C#
Учебное пособие
Под общейредакцией
кандидата технических наук, профессора В. В. Турупалова
Москва Вологда
«Инфра-Инженерия»
2023
УДК 004.432:004.514(075.8)
ББК 32.973+85.15
М29
Рецензенты:
доктор технических наук, профессор кафедры компьютерных
технологий и программной инженерии
ФГАОУ ВО «Санкт-Петербургский государственный университет
аэрокосмического приборостроения» Скобцов Юрий Александрович;
доктор технических наук, профессор, заведующий кафедрой
прикладной математики Донецкого национального технического
университета Павлыш Владимир Николаевич
Мартыненко, Т. В.
М29 Основы визуального программирования в среде Visual Studio
на базе C# : учебное пособие / Т. В. Мартыненко, В. В. Турупалов,
Н. К. Андриевская ; под общ. ред. к. т. н., проф. В. В. Турупалова. -
Москва ; Вологда : Инфра-Инженерия, 2023. - 232 с. : ил., табл.
ISBN 978-5-9729-1225-4
Рассматриваются вопросы создания визуальных приложений с ис¬
пользованием стандартных элементов управления. Содержится описание
языка программирования С#, что позволяет читателю легче усвоить при¬
веденные примеры.
Для студентов, обучающихся по направлениям подготовки в рамках
укрупненных групп 02.00.00 «Компьютерные и информационные науки»,
09.00.00 «Информатика и вычислительная техника», 10.00.00 «Информа¬
ционная безопасность», 11.00.00 «Электроника, радиотехника и системы
связи», 12.00.00 «Фотоника, приборостроение, оптические и биотехниче¬
ские системы и технологии», 27.00.00 «Управление в технических систе¬
мах» и 38.00.00 «Экономика и управление». Может быть полезно практи¬
кам, которые имеют значительный опыт разработки приложений в среде
Windows.
УДК 004.432:004.514(075.8)
ББК 32.973+85.15
ISBN 978-5-9729-1225-4 © Мартыненко Т. В., Турупалов В. В., Андриевская Н. К.., 2023
© Издательство «Инфра-Инженерия», 2023
© Оформление. Издательство «Инфра-Инженерия», 2023
СОДЕРЖАНИЕ
ВВЕДЕНИЕ 6
1 ОБЩИЕ ПОНЯТИЯ 8
1.1 Основы объектно-событийного программирования вС# 8
1.1.1 Элементы управления 8
1.1.2 Типысвойств 12
1.1.3 События 12
1.1.4 Методы 15
1.2 Интегрированная среда разработки (IDE) 15
1.2.1 Главноеменю 16
1.2.2 Панели инструментов 16
1.2.3 Обозреватель решений 18
1.2.4 Конструктор формы и панель элементов 19
1.2.5 Окноредакторакода 22
1.2.6 Окносвойств 25
1.2.7 Утилита представления классов 32
1.2.8 Окно просмотра объектов 33
1.2.9 Настройка интегрированной среды разработки 33
1.2.10 Компоненты npoeKTaWindows Forms 35
1.2.11 Сохранение файлов проекта 35
1.3 Вопросы для повторения и контроля знаний 35
1.4 Задания для самостоятельного решения 36
2 ОСНОВЫ ПРОГРАММИРОВАНИЯ BC# 37
2.1 Переменные 37
2.2 Литералы(константы) 37
2.3 Типыданных 40
2.3.1 Классификация типов 41
2.3.2 Встроенные типы 42
2.3.3 Классификация типов данных по способу хранения 44
2.3.4 Пользовательские типы данных 46
2.3.5 Перечисления 48
2.3.6 Символы и строки 50
2.4 Область видимости переменных 52
2.5 Операции и выражения 53
2.5.1 Onepapranew 56
2.5.2 Операцииотрицания 57
2.5.3 Явноепреобразованиетипа 57
2.5.4 Условнаяоперация 57
2.5.5 Логическиевыражения 58
2.5.6 Символьныевыражения 60
2.6 Стандартные сущности 60
2.6.1 Математические функции 61
2.6.2 Структуравремениидаты 63
2.6.3 Преобразование форматов 64
2.6.4 Пользовательские форматы 66
3
2.6.5 Методы обработки строк 67
2.7 Операторы 70
2.7.1 Операторприсваивания 71
2.7.2 Условныйоператор 72
2.7.3 Управляющая структура switch 77
2.7.4 Операторы передачи управления 80
2.8 Массивы 81
2.8.1 Одномерные массивы 83
2.8.2 Прямоугольныемассивы 84
2.8.3 Ступенчатыемассивы 85
2.8.4 KnaccSystem.Array 87
2.9 Циклы 87
2.9.1 Цикл с параметром for 88
2.9.2 Цикл с предусловием while 94
2.9.3 Цикл с постусловием do 94
2.9.4 ЦиклиереборайгеасЬ 100
2.9.5 Совместное использование операторов цикла и условного оператора 101
2.10 Контроль ошибок на этапе выполнения программы 103
2.10.1 OnepaToptry 103
2.10.2 OnepaTopthrow 106
2.11 Файловый ввод-вывод 106
2.11.1 Потоки байтов 111
2.11.2 Потокисимволов 115
2.11.3 Двоичныепотоки 121
2.11.4 Использование конструкции using 129
2.12 Выводы 141
2.13 Вопросы для повторения и контроля знаний 142
2.14 Задания для самостоятельного решения 142
3 ФОРМА И ЭЛЕМЕНТЫ УПРАВЛЕНИЯ 145
3.1 Выбор и использование элементов управления 145
3.2 Работа с формами 146
3.3 Элемент управления Label (Метка или надпись) 151
3.4 Элемент управления Button (Кнопка или командная кнопка) 152
3.5 Элемент управления TextBox (Текстовое окно или текстовое поле) 154
3.6 Элемент управления CheckBox (Флажок) 157
3.7 Элемент управления RadioButton (Переключатель) 159
3.8 Контейнерные элементы управления Группа (GroupBox) и Панель (Panel) 161
3.9 Элемент управления ListBox (Список) 165
3.10 Элемент управления ComboBox (Комбинированный список) 165
3.11 ЭлементуправленияТооШр 173
3.12 Элемент управления PictureBox (Графическое поле) 173
3.13 Элемент управления ImageList 175
3.14 Элемент управления Timer (Таймер) 176
3.15 Элементы управления HScrollBar и VScrollBar (Полосы прокрутки) 177
3.16 Выводы 179
3.17 Вопросы для повторения и контроля знаний 180
3.18 Задания для самостоятельного решения 181
4 ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ... 183
4.1 Концепции объектно-ориентированного подхода 183
4.2 Классыиобъекты 183
4
4.3 Методы класса 185
4.3.1 Методы-процедуры 186
4.3.2 Методы-функции 193
4.3.3 Передача аргументов методу по ссылке и по значению 196
4.3.4 Использование форм и элементов управления как аргументов методов 196
4.3.5 Конструктор класса 197
4.3.6 Перегрузка методов 200
4.4 KnaccObject 202
4.5 Пространстваимен 203
4.6 Реализация наследования 203
4.7 Особенности инкапсуляции 205
4.8 Свойствакласса 208
4.9 Индексаторы 211
4.10 Виртуальные методы и свойства 213
4.11 Скрытие методов и свойств 216
4.12 Частичные классы 217
4.13 Абстрактные классы и члены классов 219
4.13.1 Абстрактные классы 219
4.13.2 Абстрактные члены классов 222
4.14 Интерфейсы 224
4.15 Выводы 228
4.16 Вопросы для повторения и контроля знаний 228
4.17 Задания для самостоятельного решения 228
БИБЛИОГРАФИЧЕСКОЕ ОПИСАНИЕ 230
5
ВВЕДЕНИЕ
Визуальное программирование (от лат. visualis - зрительный) -
это технология программирования, которая предусматривает созда¬
ние приложений с помощью наглядных средств. Визуальное про¬
граммирование позволяет конструировать типовое Windows-окно
приложения с параллельным написанием кода.
Следует отметить, что все программы, которые работают под
управлением Windows, имеют стандартный интерфейс пользователя
(внешний вид окон, наличие главного меню и элементов управления,
расположенных на панелях и т. д.). Это означает, что пользователи
потратят больше времени на работу с приложением и меньше на изу¬
чение меню, диалоговых панелей и комбинации клавиш.
До появления концепций визуального программирования разра¬
ботка приложений под Windows была намного тяжелее, чем процесс
создания консольных приложений. Разработчики программного обес¬
печения должны были позаботиться буквально обо всем, например,
о работе с мышью, обработке событий меню, и даже отслеживать,
щелкнул пользователь один либо два раза в конкретном месте экрана.
Разработка приложений Windows требовала экспертных знаний по
языкам программирования и сотен строк кода для выполнения про¬
стейших задач.
Visual C# (или просто C#) спроектирован специально для приме¬
нения с .NET Framework и основан на современной объектно¬
ориентированной методологии проектирования. При разработке C#
специалисты Microsoft опирались на опыт создания подобных язы¬
ков, построенных в соответствии с объектно-ориентированны¬
ми принципами. Первые наработки для объектно-ориентирован¬
ных языков программирования (ООП) были предложены еще в начале
1960-х годов. ООП позволяет разработчику моделировать объекты
определённой предметной области и позволяет использовать один
и тот же программный код в разных сферах. Применение принципов
ООП позволяет легко масштабировать уже имеющийся программ¬
ный код, а также предоставляет возможность внесения измене¬
ний в отдельные компоненты программы без затрагивания остальных
частей.
6
С помощью Visual C# можно легко и быстро создавать приложе¬
ния для Windows. Среда Visual Studio содержит большое количество
инструментов для разработки графических интерфейсов. Инструмен¬
ты Visual Studio образуют IDE - Integraty Development Environment
(интегрированная среда разработки). Благодаря использованию этих
инструментов работа, связанная с разработкой визуальных приложе¬
ний, стала значительно легче.
Учебное пособие предназначено для студентов, обучающихся по
направлениям подготовки в рамках укрупненных групп 02.00.00
«Компьютерные и информационные науки», 09.00.00 «Информатика
и вычислительная техника», 10.00.00 «Информационная безопас¬
ность», 11.00.00 «Электроника, радиотехника и системы связи»,
12.00.00 «Фотоника, приборостроение, оптические и биотехнические
системы и технологии», 27.00.00 «Управление в технических систе¬
мах» и 38.00.00 «Экономика и управление».
Учебное пособие охватывает вопросы создания визуальных при¬
ложений с использованием стандартных элементов управления. Вто¬
рой раздел в сжатой форме содержит описание языка программирова¬
ния C#, что позволяет читателю легче усвоить приведенные в учеб¬
нике примеры. Рассмотренные элементы концепции объектно¬
ориентированного программирования позволяют повысить качество
разрабатываемых визуальных приложений. Предполагается, что чита¬
тель уже имеет опыт написания программ и разработки алгоритмов.
Авторы
7
1 ОБЩИЕ ПОНЯТИЯ
1.1 Основы объектно-событийного программирования в C#
1.1.1 Элементы управления
Процесс создания Windows-приложения состоит из двух основ¬
ных этапов:
1) визуальное проектирование, то есть задание внешнего облика
приложения;
2) определение поведения приложения.
Основным окном разрабатываемого приложения является форма.
Визуальное проектирование заключается в помещении на форму эле¬
ментов управления (компонентов) и задании их свойств (размер, по¬
ложение на экране, цвет и пр.) и свойств самой формы.
Каждый элемент управления обладает набором свойств.
Свойства - это атрибуты (основные характеристики), которые
описывают особенности объекта, например: цвет, высота, ширина и
положение объекта. На внешний вид объекта можно воздействовать
(изменять его) во время разработки и выполнения приложения, изме¬
няя его свойства.
Практически все элементы управления реагируют на определён¬
ные события от мыши и клавиатуры.
Приложения Windows используют методы (процедуры) обработ¬
ки событий для управления взаимодействием между программой и
пользователем и для реакции на действия операционной системы
(ОС). Программный код, разрабатываемый с использованием C#,
будет обеспечивать реакцию на события. Процедура, которая реаги¬
рует на событие, называется обработчиком события. Visual C# рабо¬
тает с событиями путём вызова определённых процедур - обработчи¬
ков событий. Если процедура не связана с данным событием, то оно
игнорируется и выполняется стандартная реакция системы или не
производится никакого действия.
Для элементов управления, представленных в Visual C#, суще¬
ствует набор свойств, которые присущи фактически всем элементам
управления (табл. 1.1).
8
Таблица 1.1 - Общие свойства элементов управления
Свойство
Описание
Anchor
Указывает поведение элемента управления при изменении
размеров его контейнера
BackColor
Цвет фона элемента управления
BackgroundImage
Устанавливает или возвращает фоновое изображение,
размещаемое внутри элемента управления.
Cursor
Вид указателя мыши при позиционировании указателя
на элементе управления
Dock
Пристыковывает элемент управления к краям его контейнера
Enabled
Установка значения свойства Enabled равным true
означает, что элемент управления может принимать данные,
вводимые пользователем. Установка этого значения равным
false означает невозможность приема этих данных
Font
Шрифт, используемый для отображения текста на элементе
управления
ForeColor
Цвет текста надписи на элементе управления
Location
Положение элемента управления на поверхности формы
или формы на поверхности экрана. Уточняющее свойство х
определяет расстояние от левой границы элемента
управления до левой границы формы/экрана, уточняющее
свойство у - от верхней границы элемента управления
до верхней границы клиентской области
Name
Имя элемента управления. Это имя может использоваться
для ссылки на элемент в программном коде.
Size
Размер элемента управления. Уточняющее свойство Width
определяет ширину, свойство Height - высоту
TabIndex
Порядковый номер элемента управления
в последовательности перехода между элементами
управления внутри его контейнера по клавише табуляции
Tabstop
Указывает доступность элемента управления по клавише
табуляции
Text
Содержит текст, связанный с данным элементом
управления
ToolTip
Получает или задает содержимое подсказки в случае
помещения на форму соответствующего элемента
управления подсказки
Visible
Указывает видимость элемента управления во время
выполнения
9
Следует отметить, что существует два свойства, которые отвеча¬
ют за более точное расположение элементов управления на форме.
Это Margin и Padding.
Свойство Margin определяет пространство вокруг элемента
управления, которое обеспечивает определенное расстояние между
границами этого элемента управления и другими элементами.
Свойство Padding определяет пространство внутри элемента
управления, которое обеспечивает определенное расстояние между
содержимым элемента управления (например, значением свойства
Text) и границами элемента управления.
На рисунке 1.1 показаны различия между свойствами Padding
и Margin элемента управления.
Внешнее поле
Внутреннее поле
' Margin
Padding
Рисунок 1.1 - Различие между свойствами Padding и Margin
элемента управления
Для обоих свойств можно задать отдельные значения как для
всех границ (All), для правой (Right), левой (Left), верхней (Top),
нижней (Bottom).
Отдельно следует рассмотреть свойства Anchor и Dock, которые
используются на этапе конструирования формы. Необходимость ис¬
пользования этих свойств - предотвращение искажения формы при
изменении размеров окна пользователем. Раньше для решения этой
задачи требовалось написание множества строк кода. Следует отме¬
тить, что свойства Anchor и Dock будут применены к элементу
управления только в том случае, если AutoSize имеет значение true.
10
Свойство Anchor указывает поведение элемента управления при
изменении размеров родительского элемента управления (контейнера,
окна) пользователем. Можно указать, чтобы элемент управления из¬
менял свои размеры, сохраняя пропорции своих краев, либо сохранял
свои размеры и позицию относительно краев родительского элемента.
Свойство Dock указывает, что элемент управления должен при¬
стыковываться к краю своего контейнера. Если пользователь изменя¬
ет размеры окна, элемент управления остается пристыкованным к его
краю. Если, например, указать, что элемент управления должен быть
пристыкован к нижнему краю своего контейнера, то элемент управ¬
ления изменяет свои размеры и/или перемещается, чтобы всегда за¬
нимать нижнюю часть окна независимо от изменения его размеров.
Пример применения свойства Dock с различными значениями, приве¬
ден на рисунке 1.2.
Рисунок 1.2 - Пример применения свойства Dock с различными
значениями
Большая часть свойств задается в режиме конструирования, хотя
большинство из них может изменяться и во время выполнения при¬
ложения. Для этого необходимо обратиться к элементу управления
и указать название свойства через точку:
[имяФормы.]имяЭлементаУправления.свойство
Например, buttonl.BackColor = Color.Green -измене¬
ние цвета кнопки на зеленый.
11
1.1.2 Типы свойств
Проанализировав все указанные выше свойства можно выделить
следующие типы свойств.
1. Числовой. Свойства такого типа принимают числовые значения
(как правило, целые). Например, размер объекта Width (ширина)
и Height (высота). Свойства данного типа изменяются непосредственно
в окне свойства или при изменении размеров с помощью мыши.
2. Строковый. В окне свойства необходимо набрать текст.
Например, Text (заголовок формы) или Name (имя объекта).
3. Логический. Свойства такого типа могут принимать только два
значения «true» или «false». Например, свойство «Visible» (види¬
мость). Изменение свойства логического типа возможно или выбором
значения из предлагаемых вариантов, или двойной щелчок мыши
в поле свойства изменяет его значение на противоположное.
4. Фиксированный набор значений. Требуемое значение свойства
выбирается из предлагаемого списка, либо двойной щелчок мыши
в окне свойства перебирает все варианты. Например, свойство
«WindowState» для формы может принимать одно из значений:
- Normal;
- Minimized;
- Maximized.
В некоторых случаях для задания фиксированного значения мо¬
гут использоваться специальные конструкторы (например, свойства
Dock, Anchor). Для установки значения цвета (например, свойства
Backcolor, Forecolor) используются палитры цветов.
5. Файловый тип содержит имя файла, из которого берется значе¬
ние свойства. Например, свойство BackgroundImage для формы
отображает значок, рисунок, который записан в выбранном файле.
1.1.3 События
ОС Windows управляет выполнением программ с помощью се¬
рии событий. Событие определяет, в каком состоянии находится объ¬
ект или что с ним происходит.
12
Пример 1.1. Возникновение серии событий
Работа с текстовым редактором, например, WordPad. Диалого¬
вое окно сохранения документа содержит две кнопки: «Сохранить»
и «Отменить». И диалоговое окно, и размещенные на нем элементы
(например, кнопки) являются объектами. Пользователь выполняет
щелчок левой кнопки мыши в области окна. Windows генерирует со¬
общение, описывающее эти действия, и помещает его в очередь со¬
общений программы. В данном случае этих сообщений будет два:
1) пользователь нажал левую кнопку мыши в определенной области;
2) пользователь отпустил левую кнопку мыши в определенной
области.
Из очереди сообщения доставляются соответствующему объекту,
например, форме, а та генерирует событие.
Отдельным событиям соответствует некоторый программный
код, который определяет реакцию объекта на событие. Например,
щелчок мыши в свободной области диалогового окна ни к чему не
приведет, так как с этим событием не связан программный код. При
щелчке мыши на кнопке «Сохранить» произойдет сохранение текста в
файле с указанным именем и диалоговое окно закроется. Щелчок
мыши на кнопке «Отмена» приведет просто к закрытию диалогового
окна. Все эти действия определены в соответствующих процедурах
обработки данного события.
События, которые присущи большинству элементов управления
среды, приведены в таблице 1.2.
В Visual Studio заголовки обработчиков событий выбранного
элемента управления могут формироваться автоматически в окне
программного кода. Синтаксис обработчика события:
private void
имяЭлементаУправления_событие(оЬ)есб sender,
списокПараметров)
{
//Тело обработчика
}
Где private - ключевое слово, которое определяет область дей¬
ствия (в данном случае обработчика событий);
13
Таблица 1.2 - События, которые присущи большинству элементов
управления
Событие
Описание
Click
Происходит при щелчке на элементе управления. В некоторых случаях это
событие происходит также при нажатии пользователем клавиши <Enter>
Doubleclick
Происходит при двойном щелчке на элементе управления. Иногда
обработка события Click для некоторых элементов управления
полностью исключает возможность вызова события DoubleClick
DragDrop
Происходит по завершении операции перетаскивания и отпускания,
т. е. при перетаскивании объекта поверх элемента управления
и освобождении кнопки мыши пользователем
DragEnter
Происходит, когда перетаскиваемый объект перемещается внутрь границ
элемента управления
DragLeave
Происходит, когда перетаскиваемый объект покидает границы элемента
управления
DragOver
Происходит, когда объект перетаскивается поверх элемента управления
Происходит, когда элемент управления получает фокус (элемент
Enter
выбран). Это событие не следует использовать для проверки
корректности вводимых данных. В этом случае вместо него следует
применять события Validating и Validated
Leave
Происходит, когда элемент управления теряет фокус (переход к другому
элементу). Это событие не следует использовать для проверки
корректности вводимых данных. В этом случае вместо него следует
применять события Validating и Validated
KeyDown
Происходит при нажатии, в то время как элемент управления находится в
фокусе. Это событие всегда происходит прежде событий KeyPress и KeyUp
KeyUp
Происходит при освобождении клавиши, в то время как элемент
управления находится в фокусе. Это событие всегда происходит
после событий KeyDown и KeyPress
KeyPress
Происходит при нажатии клавиши, в то время как элемент управления
находится в фокусе. Это событие всегда происходит после события
KeyDown и перед событием KeyUp. Различие между событиями
KeyDown и KeyPress состоит в том, что KeyDown передает код нажатой
клавиши, a KeyPress - соответствующее значение char клавиши
MouseMove
Происходит непрерывно в процессе перемещения указателя мыши над
элементом управления
MouseDown
Происходит при помещении указателя мыши над элементом управления
и нажатии кнопки мыши. Это событие не эквивалентно событию Click,
поскольку MouseDown происходит сразу после нажатия кнопки мыши
и перед ее освобождением
MouseUp
Происходит при помещении указателя мыши над элементом управления
и освобождении кнопки мыши
Paint
Происходит при прорисовке элемента управления
Resize
Происходит при изменении размеров элемента управления
Validating
Запускается, когдаэлементуправления, свойство CausesValidation которого
установлено равным true, готов принять фокус. Проверяемым элементом
управления является тот, который теряет фокус, а не тот, который его получает
Validated
Запускается, когда элемент управления, свойство CausesValidation
которого установлено равным true, готов принять фокус. Это событие
запускается по завершении события Validating, и оно указывает на
завершение проверки
14
object sender - элемент управления, который генерирует собы¬
тие;
списокПараметров - список аргументов, которые передаются
в процедуру и несут информацию о событии.
1.1.4 Методы
Элементы управления, реализованные в стандартной библиотеке
.NET Framework, как и в большинстве других объектно¬
ориентированных библиотек, содержат методы, которые работают
как процедуры или функции. Методы обеспечивают выполнение тех
или иных действий, изменение данных, но принадлежат конкретным
объектам.
Для того чтобы вызвать метод, указывается имя объекта и через
точку имя метода:
[имяФормы.]имяЭлементаУправления.имяМетода([пара
метры])
1.2 Интегрированная среда разработки (IDE)
Понятие интегрированная среда разработки (IDE) включает ин¬
терфейс и среду, в которой разрабатываются приложения. Среда
называется интегрированной, поскольку с экрана можно вызвать бук¬
вально любой необходимый инструмент.
IDE Visual Studio состоит из нескольких основных компонентов:
главное меню, панель инструментов, окно проекта, окно свойств, ок¬
но макета формы, панель элементов, конструктор форм, окно про¬
смотра объектов. Оболочка IDE (рис. 1.3) выполнена в виде приложе¬
ния, имеющего каркас с расположенной внутри рабочей областью,
в которой размещаются множественные редакторы кода - текстовые
и графические (конструктор).
Рассмотрим эти компоненты подробнее.
15
Рисунок 1.3 - Интегрированная средаразработки Visual Studio
1.2.1 Главное меню
Главное меню интегрированной среды разработки типично для
программ, разработанных под Windows. Пункты главного меню и их
назначение приведены в таблице 1.3.
1.2.2 Панели инструментов
В IDE Visual Studio предусмотрено большое число панелей ин¬
струментов, которые призваны ускорить доступ к основным коман¬
дам среды при разработке проектов.
Инструментальные панели, как вспомогательные окна, для удоб¬
ства их использования могут находиться в свободном плавающем или
закрепленном в рабочую область состоянии.
Приклеенная панель может автоматически выдвигаться в сторону
рабочей области из каркаса оболочки при наведении на нее курсора
мыши. Изменение поведения панелей возможно с помощью кон-
16
текстного меню заголовка окна (рис. 1.4) или перетаскиванием за за¬
головок с рамки каркаса оболочки. Для закрепления на экране панели
инструментов используется пиктограмма !.
Таблица 1.3 - Пункты главного меню
№
Пункт
Назначение
1.
Файл
Предназначен для работы с файлами, из которых состоят
приложения
2.
Правка
Позволяет выполнять операции обмена, как с фрагментами
текста, так и с элементами
3.
Вид
Содержит режимы просмотра различных компонентов
и инструментов
4.
Проект
Является основным пунктом. В нем добавляются
и удаляются формы, программные модули,
пользовательские управляющие элементы и т. п.
5.
Сборка
Позволяет собрать, пересобрать отдельные файлы
и компоненты проекта, которые были изменены с момента
последней сборки. Также позволяет очистить решение
от промежуточных и выходных файлов
6.
Отладка
Используется при отладке приложения. Также позволяет
выполнять запуск, остановку, прерывание и возобновление
работы приложения
7.
Формат
Позволяет управлять расположением визуальных элементов
управления и используется для конструктора форм
8.
Средства
Обеспечивает настройку IDE и вызов отдельных
служебных программ (утилит)
9.
Окно
Позволяет осуществлять переход между окнами среды
10.
Справка
Содержит справочную информацию об интегрированной
среде разработки приложений, об управляющих элементах,
операторах, функциях и процедурах языка C#
17
Рисунок 1.4 - Вызов контекстного меню инструментальной панели
Установка/удаление панелей инструментов из оболочки IDE
осуществляется выбором (щелкнуть левой кнопкой) пункта меню
«Вид» -> «Панель инструментов» и в появившемся списке щелчком
мыши установить или удалить «галочку» напротив нужной панели.
Настройка панелей инструментов, то есть удаление или добавле¬
ние элементов, осуществляется после выбора пункта «Настройка...».
1.2.3 Обозреватель решений
В верхней правой части окна Visual Studio (рис. 1.3) располага¬
ется окно управления проектом. В случае если окно Обозревателя
проекта не отображается, следует воспользоваться командой
«Вид» -^-«Обозреватель решений» главного меню. В данном окне
можно выбрать нужный для редактирования элемент: файл кода,
форму и т.д. В соответствии с этим меняется редактор в левой части.
Для формы отображается редактор формы, называемый еще кон¬
структором формы. При редактировании кода открывается текстовый
редактор. Выбор редактируемого в обозревателе проекта элемента
осуществляется двойным щелчком.
При помощи обозревателя проекта также можно создавать новые
каталоги и файлы, добавлять существующие файлы в проект, исклю¬
чать файлы из проекта или удалять их физически. В этом же окне вы¬
полняется добавление ссылок на сборки (DLL) стандартных (.NET
Framework) или пользовательских библиотек.
18
Через пиктограмму «Свойства» панели инструментов окна «Обо¬
зреватель решений» можно вызывать окно редактора конфигура¬
ции проекта. То же самое можно сделать командой меню «Про¬
ект» -> «Свойства: имяПроекта» или командой «Свойства» кон¬
текстного меню имени проекта. В таблице 1.4 указано назначение
пиктограмм встроенной панели инструментов оконной утилиты
«Обозреватель решений».
Панель «Обозреватель решений» имеет развитое контекстно¬
зависимое меню, команды которого обычно применяются ко всему
проекту. Часть команд дублируется в разделах «Проект» и «Правка»
основного меню оболочки.
1.2.4 Конструктор формы и панель элементов
Конструктор формы имеет три маркера для изменения размера
формы. С их помощью можно увеличить или уменьшить размер фор¬
мы по высоте и ширине или одновременно по обоим параметрам про¬
порционально (рис. 1.5).
Обычно окно конструктора формы используют совместно с пане¬
лью элементов (пункт меню «Вид» ->-«Панель элементов»). В окне
предлагается большое количество .NET-элементов управления, кото¬
рые можно добавлять в разрабатываемое приложение (рис. 1.6).
Панель элементов управления содержит стандартный набор: ок¬
на, кнопки, полосы прокрутки и т. д., из которых складывается ин¬
терфейс приложения. Наиболее часто применяющиеся при разработке
графических интерфейсов элементы управления и их основные свой¬
ства будут рассмотрены далее.
Кроме стандартных, имеются другие элементы управления, све¬
дения о которых можно получить во встроенной справочной системе
Visual Studio и которые можно добавлять к основному списку.
19
Таблица 1.4 - Пиктограммы панели «Обозреватель решений»
Пиктограмма
Значение
а
Обозреватель решений
е а □. • # '® • 5 & * й ,
Обозреватель решений - поисч tCIrl.-;} ^Свойства [Alt* ВВОД |
Я Решение "WindowsFormsApp2" (проектов: 1)
У -I
> f* Properties
|> Ссылки
WindowsFormsApp2
Вызывает окно редактора
конфигурации проекта
Отображает или скрывает
второстепенные каталоги
проекта
Обозреватель решений
О п! - # т© • t; 6 ЙП Г® >*
Обозреватель решений — поиск (Ctrl
RI Решение "WindowsFormsApp2" i
Обновить
ifjutKiub: ij
WindowsFormsApp2
1 I
> Properties
> Ссылки
Читает с диска обновленную
структуру проекта
Открывает окно редактора
кода
Для добавления нового элемента необходимо щелкнуть правой
кнопкой мыши в области панели элементов и в появившемся перечне
выбрать пункт «Выбрать элементы...». Появится перечень файлов с
новыми управляющими элементами (рис. 1.7).
Для размещения новых элементов на дополнительной вкладке
сначала необходимо создать вкладку, щелкнув правой кнопкой мыши
в области панели элементов, и в контекстном меню выбрать пункт
«Добавить вкладку».
20
Файл Правка Вид Пдоект Сборка Отладка Команда Nsight Формат
О * О I tg > й Н В4 *9 - Q* - Debug - Any CPU - ► Пуск
IHHB
Рисунок 1.5 - Окно конструктора формы
Рисунок 1.6 - Панель элементов управления
21
Рисунок 1.7 - Диалоговое окно для выбора новых элементов
управления
1.2.5 Окно редактора кода
При щелчке на кнопке «Перейти к коду» (табл. 1.2) открывается
окно кода (текста программы), относящееся к активной форме с рас¬
положенными на ней управляющими элементами. Текст представляет
собой каркас, в который программист добавляет код по мере необхо¬
димости. По умолчанию ключевые (зарезервированные) слова отоб¬
ражаются синим цветом, комментарии различных типов - серым и
темно-зеленым, остальной текст - черным. Слева от текста находятся
символы структуры: щелкнув на любом квадратике с минусом, можно
скрыть соответствующий блок кода. При этом минус превращается в
плюс, щелкнув на котором можно опять вывести блок на экран. Это
средство хорошо визуально структурирует код и позволяет сфокуси¬
ровать внимание на нужных фрагментах.
Окно программного кода (рис. 1.8) содержит поля со списком
проектов, классов и их элементов, а также текстовое поле для написа¬
ния программы.
22
Рисунок 1.8 - Окно редактора кода
Поле «Классы» содержит список классов, описанных в текущем
файле. Третий список включает перечень элементов выбранного
класса: процедуры обработки событий, относящиеся к элементам
управления формы, а также атрибуты и методы класса.
Каждому управляющему элементу в C# поставлен в соответствие
определенный набор событий, которые происходят в процессе вы¬
полнения приложения. В свою очередь, события ставятся в соответ¬
ствие процедурам обработки (процедура в языках программирования
состоит из набора операторов, выполняемых после ее вызова). То есть
событие может вызвать программное изменение данных.
При добавлении нового обработчика события в поле ввода текста
программы автоматически формируется заголовок процедуры и ко¬
нечный оператор. Имя процедуры формируется автоматически IDE
и состоит из двух частей, разделенных подчеркиванием. Имя выбран¬
23
ного на форме элемента управления и имя события (например, строки
button2_Click вместе с открывающейся и закрывающейся фигурной
скобочкой определяют первый и последний оператор процедуры об¬
работки события щелчка мышью по кнопке button2).
Рисунок 1.9 - Редактирование программного кода
в Visual Studio
Кроме того, по мере ввода кода выполняется его синтаксическая
проверка, а код, вызывающий появление ошибок в процессе компи¬
ляции, выделяется. Редактор кода располагает также средством
IntelliSense, обеспечивающим автоматическое отображение имен
классов, полей или методов, при начале их ввода. Аналогичным обра¬
зом, по мере ввода имен параметров методов, редактор отображает
список параметров для всех перегруженных версий, предусмотрен¬
ных для данного метода. Действие IntelliSense на примере одного из
базовых классов C#, ListBox, показано на рисунке 1.10.
24
Form1.Designer.es*
Form1.cs [Конструктор]*
-
ИЗ ovp_31
ovp_31,Forml
~ © FormlQ
-II
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
В namespace ovp_31
{
□ ! public partial class Forml : Form
bool f = true;
public FormlQ
{
InitializeComponentQ;
textBoxl.Text =
listBoxl.jt_e_.
f Drawltem
private void
100 % - A
{
© GetltemHeight
toolstrip® GetltemRectangle
antArgs e)
aBHid 'Выход'
гите выйти из программы?:
ListBox.ObjectCollection ListBox.Items { get;
Возвращает элементы ListBox.
ct sender, EventArgs e)
if (Messa© GetltemText
{ ItemHeight
this,
^ 9 Measureltem
J* Selected Item
private void J* Selectedltems
{ f ©
textBoxl. .
textBoxl.Text += textBox2.SelectedText.To5tringQ;
textBoxl.Readonly = true;
toolStripStatusLabel2.Text = textBox2.SelectedText.ToString();
private void Forml_Load(object sender, EventArgs e)
Рисунок 1.10 - Действие средства IntelliSense
1.2.6 Окно свойств
Каждый элемент формы и сама форма обладают набором специ¬
фических свойств, параметры которых определяют их внешний вид и
поведение при работе программы, например: цвет, размер, положение
на форме. Список параметров и их значений определяются в окне
свойств.
Раскрывающийся список объектов в верхней части окна (рис. 1.11)
содержит имена и типы объектов (элементов), помещенных на форму,
а также самой формы. Изначально список содержит только форму,
каждый новый элемент, помещаемый на форму, включается в список.
Таким образом, просмотр свойств конкретного объекта возможен при
его выборе в окне проекта или в списке, размещенном на панели
свойств.
25
Для выбранного из списка элемента вы¬
водится перечень свойств и их значений. Зна¬
чение выделенного подсветкой свойства мож¬
но изменять. Список свойств можно упорядо¬
чить по алфавиту S3 или по категориям °i!.
Стандартное окно свойств содержит два
основных режима работы, которые можно пе¬
реключать кнопками ® и ^ . Первая кнопка
переключает на закладку свойств объекта.
Здесь собраны все свойства, которые позво¬
ляют посмотреть и изменить выбранный объ¬
ект. Вторая кнопка переключает на закладку
«События», которая содержит список собы¬
тий, доступных для выбранного объекта.
Каждое свойство, в зависимости от его
типа, имеет свой редактор свойств. Среда
Visual Studio предоставляет редакторы для
всех стандартных свойств, которые показаны
нарисунках 1.12 - 1.18:
- простой редактор текстовых и число¬
вых полей позволяет изменять все свойства
с типом string, int ит.п.;
- редактор выбора из списка позволяет модифицировать
перечисления (enum), а также свойство типа bool (выбор из списка
true/false);
- редактор цветов позволяет редактировать свойства типа Color;
- редактор шрифтов позволяет изменять шрифт или каждую из
его составляющих с помощью специального диалога;
- редакторы свойств TextAlign и Dock показывают специальные
диалоговые окна.
Рисунок 1.11 -
Окно свойств
26
I Свойства
-
X
Buttonl System.Windows.Forms,Button »
а [Е ИЗ*
/•
Locked
False
Е Margin
3; 3; 3; 3
Б MaximumSize
0; 0
Б MinimumSize
0; 0
Modifiers
Friend
Б Padding
0; 0; 0; 0
RightToLeft
No
Б Size
75; 23
Tablndex
2
1
TabStop
True
Tag
Ц Text
Название кн
□
TextAliqn
MiddleCenter
Text
Текст, связанный
с элементом
управления,
Рисунок 1.12 - Редактор простого Рисунок 1.13 - Редактор выбора
(текстового или числового) поля из списка
Рисунок 1.14 - Редактор
цветов
Рисунок 1.15 - Задание свойств
шрифта
27
Шрифт
X
Видоизменение
I I Зачеркнутый
I I Подчеркнутый
Образец
АаВЬБбФф
Набор символов:
|Кириллица
'П
Рисунок 1.16 - Редактор шрифта
Рисунок 1.17 - Редактор
выравнивания (свойство TextAlign)
Рисунок 1.18 - Редактор
привязки (свойство Dock)
28
Пример 1.2. Создание проекта C# Windows Forms
После запуска Visual Studio необходимо выбрать пункт меню
«Файл» -> «Создать» -> «Проект». В появившемся диалоговом
окне необходимо выбрать язык (Visual C#) и тип приложения (При¬
ложение Windows Forms). Далее указать имя проекта, местополо¬
жение и платформу. Следует отметить, что расположение проектов
на диске с установленной операционной системой не рекомендуется
(рис. 1.19).
Рисунок 1.19 - Окно создания проекта
Добавление нового элемента проекта, например формы Form2
можно осуществить с помощью контекстного меню «Обозревате¬
ля решений». Последовательность подпунктов представлена на ри¬
сунке 1.20.
29
Рисунок 1.20 - Создание новой формы с помощью обозревателя
решений
Тип и имя нового элемента проекта задается с помощью специ¬
ального диалогового окна (рис. 1.21).
Рисунок 1.21 - Выбор типа и задание имени нового элемента проекта
Графические интерфейсы пользователя часто используют допол¬
нительные файлы: текстовые (*.txt, *.xml, *.csv), графические (*.jpg,
*.bmp) и т. д. Зачастую для расположения этих файлов в проекте
30
необходимо создать дополнительную папку, например «Resources»,
что также может быть реализовано с использованием контекстного
меню «Обозревателя решений». При этом в меню необходимо вы¬
брать добавление существующего элемента, указать фильтр для фай¬
лов (рис. 1.22). Добавленные таким образом файлы отобразятся в окне
обозревателя решений (рис. 1.23).
Рисунок 1.22 - Добавление существующих элементов в проект
Рисунок 1.23 - Список файлов проекта
31
1.2.7 Утилита представления классов
Этот инструмент обеспечивает возможность обзора всех типов
(классы, структуры, перечисления-перечни, интерфейсы, делегаты),
входящих в проект, вместе с их пространствами имен. Для открытия
окна «Представление классов» используется пункт меню
«Вид» ^-«Классы», или сочетание клавиш <Ctrl + Shift + C>. Верх¬
няя половина панели отображает множество пространств имен и их
типов, а нижняя - члены (методы, свойства, события, поля) выбран¬
ного в настоящий момент типа (рис. 1.24).
Представление классов
о о о -
• р
л ^ Forml
л в Базовые типы
л ^5 Form
л ContainerControl
л ScrollableControl
[> ^5 Control
^ lArrangedElement
-о
►О IDisposable
-о IContainerControl
t> Program
{} оvp_31.Properties
A* Site
£ Disposed
Рисунок 1.24 - Окно
представления классов
Выбор в контекстном меню любого элемента пункта «Найти
определение», позволяет перейти к месту программы в окне редакто¬
ра кода, в котором находится определение данного элемента. Кроме
того, контекстное меню позволяет добавить в класс поле, метод,
свойство или индексатор, т. е. установить детальные характеристики
соответствующего элемента в диалоговом окне, и автоматически сге¬
нерировать соответствующий код.
32
1.2.8 Окно просмотра объектов
Окно просмотра объектов вызывается командой «Вид» -> «Обо¬
зреватель объектов» (рис. 1.25). С его помощью можно получить спи¬
сок элементов или модулей выбранного проекта. Для выбранных эле¬
ментов выводится список методов и свойств, их краткая аннотация
и развернутая справка.
1 Обозреватель объектов
: » П
X
Обзор:
Все компоненты
■ • • O 1. о ■
<Поиск>
• p
» О
<CpplmplementationDetails>
©
AcceptChangesQ
-
> О
< CrtlmplementationDetails>
©
Begin Ed itQ
> О
М i crosoft. Sq 1 Server, Server
©
Cancel EditQ
> {1
System.Configu ration
©
ClearErrorsQ
л {}
System. Data
©
DeleteQ
1
>
# AcceptRejectRule
©
EndEditO
>
в3 CommandBehavior
©
GetChi 1 dRows(String) As System,Data,DataRowQ
>
в3 CommandType
©
GetCh ildRows(String, System.Data.DataRowVersion) As System, Data, Data RowO
>
a3 ConflictOption
©
GetCh ildRowsfSystem.Data, Data Relation) As System, Data, DataRowO
>
в3 Connection State
©
GetCh ildRowsfSystem. Data, Data Relation, System.Data.DataRowVersion) As System, Da
>
Constraint
©
GetColumnError(lnteger) As String
>
ConstraintCollection
©
GetColumnError(String) As String
>
ConstraintException
©
GetColumnError(System, Data, Data Column) As String
>
Data Column
©
GetColumnsInErrorQ As System.Data.DataColumnQ
>
*ij DataColumnChangeEventArg:
©
GetParentRow(Strinq) As Svstem.Data.DataRow
> s DataColumnChangeEventHan
> DataColumnCollection
> Data Exception
> Л} Data Relation
> DataRelationCollection
> *ij
> в3 DataRowAction
Public Class DataRow
Inherits Object
Элемент объекта System.Data
Сводка:
Представляет строку данных в System,Data,DataTable,
Рисунок 1.25 - Окно просмотра объектов
1.2.9 Настройка интегрированной среды разработки
Диалоговое окно «Параметры» («Средства» -> «Параметры...»)
позволяет выбирать панели инструментов для отображения, создавать
пользовательские панели инструментов, добавлять и удалять элемен¬
ты с панелей инструментов, а также изменять внешний вид элементов
на панелях инструментов.
Левая часть окна «Параметры» (рис. 1.26) позволяет выбрать од¬
ну из категорий настройки среды. Основные категории приведены
в таблице 1.5.
33
Рисунок 1.26 - Окно настройки интегрированной среды
Таблица 1.5 - Назначение категорий окна «Параметры»
Категория
Назначение
Окружение
Настройка среды разработки
Общие
Общая настройка IDE: цветовая схема, отображение или
скрытие статусной строки, оптимизация отображения и т. п.
Автовосстановление
Задает временной промежуток для автоматического
восстановления данных
Шрифты и цвета
Определение настроек шрифта, цвета элемента и цвета
фона. Элемент среды, для которого устанавливаются
значения, выбирается в специальном выпадающем
списке «Параметры для:»
Клавиатура
Назначение сочетания клавиш для вызова команд
Проекты
и решения
Настройка расположения проектов, отображение окна
ошибок, отображение активного элемента в Обозревателе
решений и т. д.
Текстовый
редактор
Настройка редактора кода: автоматическое добавление кода
в конец программы; отображение линий, разделяющих
процедуры; подсказки при обнаружении синтаксической
ошибки и т. п.
Общие
Автоматически отображать список членов, задавать номера
строк
IntelliSense
Настройка списков для завершения, поведения фрагментов
кода, реакция текстового редактора на клавишу <Enter>
Конструктор
Windows Forms
Настройка конструктора форм: установка наличия сетки,
ее размеров, а также привязки к сетке
34
1.2.10 Компоненты проекта Windows Forms
Проект может содержать следующие компоненты:
- точка входа в приложение (файл Program.cs);
- файл каждой формы с элементами управления (*.Designer.cs);
- файл каждого класса (*.cs);
- файл ресурсов (*.resx);
- файл проекта, содержащий ссылки на свои компоненты
(*.csproj).
1.2.11 Сохранение файлов проекта
При сохранении проекта и его компонентов следует учитывать
некоторые особенности.
При нажатии кнопки сохранения на панели инструментов Visual
Studio сохраняется активный компонент проекта. Для сохранения
всего проекта и составляющих его компонентов необходимо вызвать
команду «Файл» -> «Сохранить все». При этом сохраняются и от¬
дельные компоненты.
Помните, что в файле компонента не сохраняется информация
о том, какому проекту он принадлежит. Список компонентов проекта
и все связи между компонентами сохраняются только в файле проекта
(csproj).
Таким образом, в других проектах можно использовать некото¬
рую составную часть любого проекта, например модуль, форму и т. д.
Но для этого следует скопировать в каталог проекта нужный файл
или файлы и добавить их в проект командой «Проект» ^ «Доба¬
вить...».
1.3 Вопросы для повторения и контроля знаний
1. Определите основные типы свойств элементов управления.
2. Укажите способы открытия окна редактора кода.
3. Какие основные составные части окнаредактора кода?
4. Как организовать перемещение по управляющим элементам
в заданном порядке с помощью клавиши <Tab>?
35
5. Определите основные средства настройки интегрированной
среды разработки.
6. Что значит установка автоматического списка членов?
7. Каким образом можно открыть окно просмотра объектов?
8. Основные составные части окна просмотра объектов.
9. Как организовать пропуск управляющих элементов при пере¬
ходе по ним с помощью клавиши <Tab>?
1.4 Задания для самостоятельного решения
1. На панели элементов добавить вкладку и присвоить ей имя
«Дополнение». На эту вкладку поместить элементы: LabelArray,
CheckBoxArray и TextBoxArray.
2. В категории «Расположения» окна «Параметры» изменить ме¬
сто размещения проектов. Перезапустить IDE и проанализировать,
что изменилось при запуске.
3. В категории «Сборка и запуск» окна «Параметры» выбрать
«Предлагать выполнить сборку». Внести изменения в проект, вновь
запустить его и проанализировать, что изменилось при отладке.
4. С помощью свойств проекта изменить целевую платформу на
.NET Framework 4.5.
5. Для текущего проекта изменить пиктограмму на пользователь¬
скую.
6. Настроить цвета окна редактора кода.
36
2 ОСНОВЫ ПРОГРАММИРОВАНИЯ В C#
2.1 Переменные
Переменная является зарезервированным местом в оперативной
памяти для временного хранения данных. Каждая переменная имеет
собственное имя. Основные правила задания имен переменных:
- имя переменной может содержать любые буквы, цифры и
символ подчеркивания;
- первый символ в имени переменной должен быть буквой или
символом подчеркивания;
- в имени переменной должны отсутствовать пробелы и знаки
препинания;
- имя должно быть уникальным внутри зоны видимости;
- имя не может быть ключевым словом, например, void.
Допустимы перечисленные ниже имена переменных:
CurrentNum, Total, Date_of_birth
Следующие имена недопустимы:
2Time, $Total, Date of birth
Одно из наиболее общих соглашений по именам переменных за¬
ключается в использовании заглавных букв вначале каждого из слов,
составляющих данное имя (например, PrintIt, а не Printit). Это со¬
глашение носит название «имена переменных со смешанным реги¬
стром». Кроме этого, в наименованиях переменных можно использо¬
вать префиксы, отражающие тип переменной. При таком обозначении
переменных повышается читабельность программы и снижается ко¬
личество ошибок программирования. Префиксы отражают тип пере¬
менной и зону ее действия.
2.2 Литералы (константы)
Литералами, или константами, называют неизменяемые величи¬
ны. В C# есть логические, целые, вещественные, символьные и стро¬
ковые константы, а также константа null. Компилятор, выделив кон¬
37
станту, относит ее к одному из типов данных в зависимости от ее зна¬
чения. Разработчик может задать тип константы и самостоятельно.
Описание и примеры констант каждого типа приведены в табли-
це2.1.
Таблица 2.1 - Константы в C#
Константа
Описание
Примеры
Логическая
true (истина) или false (ложь)
true
false
Десятичная: последователь¬
ность десятичных цифр (0, 1,
2, 3, 4, 5, 6, 7, 8, 9), за кото¬
рой может следовать суф¬
фикс (U, u, L, l, UL, Ul, uL,
ul, LU, Lu, lU, lu)
8 0 199226
8u 0Lu 199226L
Целая
Шестнадцатеричная: симво¬
лы 0х или 0Х, за которыми
следуют шестнадцатеричные
цифры (0, 1,2,3, 4, 5, 6, 7, 8,
9, A, B, C, D, E, F), а за циф¬
рами, в свою очередь, может
следовать суффикс (U, u, L, l,
UL, Ul, uL, ul, LU, Lu, lU, lu)
OxA 0xlB8 0X00FF
OxAU 0xlB8LU
0X00FF1
С фиксированной точкой:
[цифры][.][цифры][суффикс]
Суффикс - один из символов
F, f, D, d, M, m
5.7 .001 35.
5.7F ,001d 35.
5F ,001f 35m
Вещественная
С порядком:
[4^pH][.][p^pH]{E|e}[+|-
][цифры] [суффикс] Суф¬
фикс - один из символов F, f,
D, d, M, m
0.2E6 .lle+3 5E-10
0.2E6D .lle-3
5E10
Символьная
Символ, заключенный
в апострофы
'A' 'Ю'
'\0' '\n'
'\xF' '\x74'
'\uA81B'
Строковая
Последовательность
символов, заключенная
в кавычки
"Здесь был Василий"
"\бЗначение r = \xF5 \n"
"Здесь был \u0056\u0061"
"C:\\temp\\filel.txt"
©"C:\temp\filel.txt"
Константа
null
Ссылка, которая не
указывает ни на какой объект
Null
38
Символьная константа представляет собой любой символ в коди¬
ровке Unicode. Символьные константы записываются в одной из че¬
тырех форм:
- «обычный» символ, имеющий графическое представление
(кроме апострофа и символа перевода строки) - 'A', 'ю', '*';
- управляющая последовательность - '\0', '\n';
- символ в виде шестнадцатеричного кода - '\xF', '\x74';
- символ в виде escape-последовательности Unicode - '\uA81B'.
Управляющей последовательностью, или простой escape-после¬
довательностью, называют определенный символ, предваряемый обрат¬
ной косой чертой. Управляющая последовательность интерпретируется
как одиночный символ и используется для представления:
- кодов, не имеющих графического изображения (например,
\n - переход в начало следующей строки);
- символов, имеющих специальное значение в строковых
и символьных литералах, например, апострофа (').
Допустимые значения последовательностей приведены в табли¬
це 2.2.
Таблица 2.2 - Управляющие последовательности в C#
Вид
Наименование
\а
Звуковой сигнал
\b
Возврат на шаг
\f
Перевод страницы (формата)
\n
Перевод строки
\r
Возврат каретки
\t
Горизонтальная табуляция
\v
Вертикальная табуляция
\\
Обратная косая черта
\'
Апостроф
\”
Кавычка
\0
Нуль-символ
Символ, представленный в виде шестнадцатеричного кода, начи¬
нается с префикса \х, за которым следует код символа. Числовое зна¬
чение должно находиться в диапазоне от 0 до 256 - 1, иначе возника¬
ет ошибка компиляции.
39
Escape-последовательности Unicode служат для представления
символа в кодировке Unicode с помощью его кода в шестнадцатерич¬
ном виде с префиксом \u или Ш, например, \u00F2, \U00010011. Коды
в диапазоне от \U10000 до \U10FFFF представляются в виде двух по¬
следовательных символов; коды, превышающие \U10FFFF, не под¬
держиваются.
Управляющие последовательности обоих видов могут использо¬
ваться и в строковых константах, называемых иначе строковыми ли¬
тералами. Например, если требуется вывести несколько строк, можно
объединить их в один литерал, отделив одну строку от другой симво¬
лами \n:
"Никто не доволен своей\пвнешностью, но каждый
доволен\псвоим умом"
Этот литерал при выводе будет выглядеть так:
Никто не доволен своей
внешностью, но каждый доволен
своим умом
В C# также имеются дословные литералы (verbatim strings). Эти
литералы предваряются символом @, который отключает обработку
управляющих последовательностей и позволяет получать строки в том
виде, в котором они записаны. Чаще всего дословные литералы при¬
меняются при задании полного пути файла. Посмотрите, насколько
лучше воспринимается второй вариант записи одного и того же пути:
"C:\\app\\bin\\debug\\a.exe"
@"C:\app\bin\debug\a.exe"
Строка может быть пустой (записывается парой смежных двой¬
ных кавычек ""). Пустая символьная константа недопустима.
Константа null представляет собой значение, задаваемое по
умолчанию для величин ссылочных типов.
2.3 Типы данных
Данные, с которыми работает программа, хранятся в оперативной
памяти. Естественно, что компилятору необходимо точно знать,
сколько места они занимают, как именно закодированы и какие дей¬
40
ствия с ними можно выполнять. Все это задается при описании дан¬
ных с помощью типа.
Тип данных однозначно определяет:
- внутреннее представление данных, а, следовательно, и мно¬
жество их возможных значений;
- допустимые действия над данными (операции и функции).
Например, целые и вещественные числа, даже если они занимают
одинаковый объем памяти, имеют совершенно разные диапазоны
возможных значений.
Каждое выражение в программе имеет определенный тип. Ком¬
пилятор использует информацию о типе при проверке допустимости
описанных в программе действий.
Память, в которой хранятся данные во время выполнения про¬
граммы, делится на две области: стек (stack) и динамическая об¬
ласть, или хип (heap), чаще называемый «кучей». Стек использует¬
ся для хранения величин, память под которые выделяет компи¬
лятор, а в динамической области память резервируется и освобож¬
дается во время выполнения программы с помощью специальных
команд. Основным местом для хранения данных в C# является ди¬
намическая память.
2.3.1 Классификация типов
В любом языке программирования типы можно классифи¬
цировать по разным признакам. Если принять за основу строе¬
ние элемента, все типы можно разделить на простые (не имеют
внутренней структуры) и структурированные (состоят из элементов
других типов). По способу создания типы можно разделить на
встроенные (стандартные) и определяемые программистом. По спо¬
собу хранения значений типы делятся на значимые, или типы-
значения, и ссылочные. Классификация типов C# приведена на ри¬
сунке 2.1.
41
Рисунок 2.1 - Классификация типов данных C#
2.3.2 Встроенные типы
Встроенные типы не требуют предварительного определения.
Для каждого типа существует ключевое слово, которое используется
при описании переменных, констант и т. д. Основные встроенные ти¬
пы данных C# приведены в таблице 2.3.
Переменная типа данных bool может принимать только два зна¬
чения: true или false. При преобразовании числовых данных в логи¬
ческие значения 0 становится false, а другие значения - true. Когда
логические значения переводятся в числовые, false становится 0,
a true - 1. По умолчанию переменной типа bool присваивается значе¬
ние false.
Для хранения целых чисел используется переменная или массив
данных типа byte.
Для текстовой информации предназначены переменные типов
char и string. Первый из них сохраняет один символ в кодировке
Unicode, а второй - строку от 0 до порядка 1 миллиарда символов
(строкой называют последовательность символов, заключенную в ка¬
вычки). Переменные типа string имеют разную длину, которая
уменьшается или увеличивается при присвоении переменным новых
значений.
42
Таблица 2.3 - Типы данных C#
Название
Ключевое
слово
Тип
.NET
Диапазон
значений
Описание
Размер,
битов
Логический
тип
bool
Boolean
true, false
Представляет
логическое
значение
8 (зависит от
разрядности
ОС)
Целые типы
sbyte
SByte
От -128
до 127
Со знаком
8
byte
Byte
От 0 до 255
Без знака
8
short
Int16
От -32768 до
32767
Со знаком
16
ushort
UInt16
От 0
до 65535
Без знака
16
int
Int32
От -2 х 109 до
2 х Ю9
Со знаком
32
uint
UInt32
От 0
до4х 109
Без знака
32
long
Int64
От -9 х Ю18
до9х Ю18
Со знаком
64
ulong
UInt64
От 0
до 18 х ю18
Без знака
64
Символьный
тип
char
Char
От U+0000 до
U+ffff
Unicode-
символ
16
Вещественные
float
Single
От 1.5 х 10'45
до 3.4 х Ю38
7 цифр
32
double
Double
От 5.0 х 10-324
до1.7х Ю308
15-16 цифр
64
Финансовый
тип
decimal
Decimal
OtI.Ox 10'28
до 7.9 х Ю28
28-29 цифр
128
Строковый тип
string
String
Длина
ограничена
объемом
доступной
памяти
Строка из
Unicode-
символов
Тип object
object
Object
Можно
хранить все,
что угодно
Всеобщий
предок
Для хранения целых значений используются переменные типа
short, int и long.
Для чисел с дробной частью предназначены типы данных double
и float, которые сохраняют числа с плавающей запятой, то есть числа,
43
представленные в виде мантиссы (число как правило, в пределах
от 1 до 10) и 10 в определенной степени, например, 4,5Е7, что означа¬
ет 4,5-107 или 45 000 000. Числа с плавающей точкой могут иметь и
отрицательный показатель степени 10, например, 4,5Е-4, что означает
4,510"4 или 0,00045. Таким образом, числа с плавающей точкой при¬
меняются для хранения как очень маленьких, так и очень больших
величин.
Тип данных object может хранить различные данные и менять их
тип во время выполнения программы.
2.3.3 Классификация типов данных по способу хранения
Чаще всего типы C# разделяют по способу хранения элементов
на типы-значения и ссылочные типы (рис. 2.2). Элементы типов-
значений, или значимых типов (value types), представляют собой
просто последовательность битов в памяти, необходимый объем ко¬
торой выделяет компилятор. Иными словами, величины значимых
типов хранят свои значения непосредственно. Величина ссылочного
типа хранит не сами данные, а ссылку на них (адрес, по которому
расположены данные). Сами данные хранятся в динамической обла¬
сти памяти.
Несмотря на различия в способе хранения, и типы-значения,
и ссылочные типы являются потомками общего базового класса
object.
На рисунке 2.3 показана разница между величинами значимого и
ссылочного типов. Одни и те же действия над ними выполняются по-
разному. Рассмотрим в качестве примера проверку на равенство. Ве¬
личины значимого типа равны, если равны их значения. Величины
ссылочного типа равны, если они ссылаются на одни и те же данные
(на рисунке b и c равны, но a не равно b даже при одинаковых значе¬
ниях). Из этого следует, что, если изменить значение одной величины
ссылочного типа, это может отразиться на другой.
44
Рисунок 2.2 - Классификация типов данных C#
по способу хранения
Рисунок 2.3 - Хранение в памяти величин значимого
и ссылочного типов
Для того чтобы величины ссылочного и значимого типов могли
использоваться совместно, необходимо иметь возможность преобра¬
зования из одного типа в другой. Преобразование из типа-значения в
ссылочный тип называется упаковкой (boxing), обратное преобразо¬
вание - распаковкой (unboxing).
45
Если величина значимого типа используется в том месте, где тре¬
буется ссылочный тип, автоматически выполняется создание проме¬
жуточной величины ссылочного типа. При необходимости обратного
преобразования с величины ссылочного типа «снимается упаковка»,
и в дальнейших действиях участвует только ее значение.
Следует отметить, что в языке C# также существуют указатели,
однако они крайне редко используются. В некоторых случаях к ним
прибегают для оптимизации приложений. Код, применяющий указа¬
тели, называют небезопасным. Блок кода или метод, в котором испо¬
льзуются указатели, помечается ключевым словом unsafe.
2.3.4 Пользовательские типы данных
Данные различных типов можно сгруппировать по какому-либо
признаку в одну удобную для использования структуру.
Оператор объявления пользовательского типа данных - структу¬
ры имеет вид:
[типДоступа] struct имяСтруктуры
{
[типДоступа] тип имяЭлементаСтруктуры1;
[[типДоступа] тип имяЭлементаСтруктуры2]
}
Оператор создает указанную структуру данных, но не выделяет
под нее память. Память выделяется оператором new, в котором в ка¬
честве типа указывается имя созданной структуры (имя пользователь¬
ского типа данных).
Пример 2.1. Объявление структуры данных студента
struct Student
{
public string surname;
public string name;
public string patronymic;
public DateTime birthday;
public byte height;
public byte weight;
46
}
//Объявление переменных типа Student
Student studentl = new Student]);
Student student2 = new Student]);
Описаны две переменные (studentl, student2), для каждой из ко¬
торых определены заданные в структуре компоненты (surname,
name, patronymic, birthday, height и weight), и для хранения значе¬
ний которых выделяется память соответственно заданному типу
(длине и способу представления).
Для обращения к конкретному элементу структуры определенно¬
го объекта используется такая запись:
имяПеременной.элементСтруктуры;
Например, studentl. birthday определяет дату рождения
студента studentl.
Аналогичным способом создания шаблона для хранения данных
пользовательского типа в C# является класс. Класс определяет, какие
данные и какую функциональность может иметь каждый конкретный
объект (называемый экземпляром) этого класса. Кроме указанных в
примере сведений о конкретном студенте, с помощью класса можно
определить функциональность, которая работает с данными, храня¬
щимися в элементах класса (полях). Набор указанных действий объ¬
единяется в метод класса.
Синтаксис описания класса:
[типДоступа] class имяКласса
{
[типДоступа] тип имяЭлементаКласса1;
[[типДоступа] тип имяЭлементаКласса2;]
[типДоступа] возвращаемыйТип имяМетода1
(спиокПараметров)
{
тело метода
}
}
47
Пример 2.2. Объявление переменных типа Student
//Объявление класса студент Student
class Student
{
public string surname;
public string name;
public string patronymic;
public DateTime birthday;
public byte height;
public byte weight;
public void printInfo()
{
MessageBox.Show("CTyfleHT " + surname);
}
}
//Объявление переменных типа Student
Student studentl = new Student();
Student student2 = new Student();
//обращение к методу класса
studentl.printInfo();
Основное отличие структур от классов в C# заключается в спосо¬
бе их хранения в памяти. Классы относятся к ссылочным типам, раз¬
мещаемым в динамической области памяти, а структуры - типы зна¬
чений, которые размещаются в стеке. Исходя из способа хранения
структуры целесообразно использовать только для небольших типов
данных, в остальных случаях в качестве пользовательского типа дан¬
ных уместнее использовать класс.
При создании классов с помощью IDE, рекомендуется каждый от¬
дельный класс помещать в соответствующий файл с расширением cs.
2.3.5 Перечисления
Перечисление объявляется с помощью ключевого слова enum,
идентифицируется по имени и представляет собой непустой список
неизменяемых именованных значений одного из встроенных типов.
48
Первое значение в перечислении по умолчанию инициализируется
нулем. Каждое последующее значение отличается от предыдущего по
крайней мере на единицу, если объявление значения не содержит яв¬
ного дополнительного присвоения нового значения. Синтаксис объ¬
явления перечисления:
enum имяПеречисления
{
имяЭлементаПеречисления1 =
значениеЭлементаПеречисления1,
[имяЭлементаПеречисления2 =
значениеЭлементаПеречисления2,
[имяЭлементаПеречисленияЫ =
значениеЭлементаПеречисленияЫ]
]
};
Пример 2.3. Объявление перечисления
enum Colors { Red = 1, Green = 2, Blue = 4,
Yellow = 8 };
Обращение к элементу перечисления осуществляется следующим
образом:
типЭлементаПеречисления имяПеременной =
имяПеречисления.имяЭлементаПеречисления;
Пример 2.4. Инициализация переменной myColor значением
перечисления
int myColor = (int)Colors.Red;
В C# перечисление является классом, который содержит методы
сравнения значений перечисления, методы преобразования значений
перечисления в строковое представление, методы перевода строково¬
го представления значения в перечисление. Наиболее часто использу¬
емые методы перечислений приведены в таблице 2.4.
49
Таблица 2.4 - Основные методы перечислений
Метод
Описание
CompareTo
Сравнение с указанным объектом.
Возвращает сведения об их относительных значениях
Format
Преобразует указанное значение заданного перечисляемого
типа в строчное представление в соответствии
с заданным форматом
GetName
Выводит имя константы в указанном перечислении,
имеющей заданное значение
GetNames
Выводит массив имен констант в указанном перечислении
GetType
Возвращает тип перечисления
GetUnderlying
Возвращает базовый тип указанного перечисления
GetValues
Выводит массив значений констант в указанном
перечислении
IsDefined
Возвращает признак наличия константы с указанным
значением в заданном перечислении
2.3.6 Символы и строки
C# для обработки текстовой информации предоставляет широкий
набор средств: отдельные символы, массивы символов, изменяемые
и неизменяемые строки и регулярные выражения.
Символы
Символьный тип char предназначен для хранения символов в ко¬
дировке Unicode. Символьный тип относится к встроенным типам
данных C# и соответствует стандартному классу Char библиотеки
.NET из пространства имен System. В этом классе определены стати¬
ческие методы, позволяющие задать вид и категорию символа, а так¬
же преобразовать символ в верхний или нижний регистр и в число.
Некоторые методы класса System.Char приведены в таблице 2.5.
Строки типа string
Тип string, предназначенный для работы со строками символов в
кодировке Unicode, является встроенным типом C#. Ему соответству¬
ет базовый класс System.String библиотеки .NET.
50
Создать строку можно несколькими способами:
string s; // инициализация отложена
// инициализация строковым литералом
string t = "qqq";
// конструктор создает строку из 20 пробелов
string u = new string(' 20);
// массив для инициализации строки
char[] а= { '0', '0', '0' };
// создание из массива символов
string v = new string( а );
Таблица 2.5 - Некоторые методы класса System.Char
Метод
Описание
GetNumericValue
Возвращает числовое значение символа, если он является
цифрой, и-1в противном случае
IsControl
Возвращает true, если символ является управляющим
IsDigit
Возвращает true, если символ является десятичной цифрой
IsLetter
Возвращает true, если символ является буквой
IsLower
Возвращает true, если символ задан в нижнем регистре
IsUpper
Возвращает true, если символ записан в верхнем регистре
IsWhiteSpace
Возвращает true, если символ является пробельным
(пробел, перевод строки и возврат каретки)
Parse
Преобразует строку в символ
(строка должна состоять из одного символа)
ToLower
Преобразует символ в нижний регистр
MaxValue,
MinValue
Возвращают символы с максимальным и минимальным кодами
(эти символы не имеют видимого представления)
Несмотря на то, что строки являются ссылочным типом данных,
на равенство и неравенство проверяются не ссылки, а значения строк.
Строки равны, если имеют одинаковое количество символов и совпа¬
дают посимвольно.
51
Обращаться к отдельному элементу строки по индексу можно
только для получения значения, но не для его изменения. Это связано
с тем, что строки типа string относятся к так называемым неизменяе¬
мым типам данных. Методы, изменяющие содержимое строки, со¬
здают новую копию строки. Неиспользуемые «старые» копии автома¬
тически удаляются сборщиком мусора.
2.4 Область видимости переменных
Область видимости (действия) данных определяет возможность
доступа к ним (например, к переменной) в отдельных процедурах од¬
ной формы или в процедурах, принадлежащих к различным формам
одной программы.
Если оператор объявления какой-либо переменной находится
внутри процедуры обработки события, то доступ к этой переменной
(возможность ее использования) возможен только в рамках данной
процедуры. Такая переменная называется локальной.
Для того чтобы одна и та же переменная могла использоваться в
разных процедурах одной формы, оператор объявления переменных
должен быть помещен в раздел класса формы. Например, если при¬
ложение выполняет вычисления, всегда используя одинаковую про¬
центную ставку, ее значение должно быть доступно всем процедурам
формы. Такие переменные называют переменными уровня класса.
Объявление переменных уровня класса происходит в разделе атрибу¬
тов класса.
Например,
public partial class FormRecord : Form
{
string filePath = "updateTestl.dat";
При использовании данной переменной выполняются следующие
правила:
- значение переменной filePath будет доступно всем про¬
цедурам, связанным с классом данной формы;
52
- все изменения этой переменной, внесенные в любую из про¬
цедур, будут сохраняться.
Очевидно, что последний пункт призывает к осторожному изме¬
нению значений переменных уровня класса. Любая информация, пе¬
редаваемая между процедурами обработки событий, является благо¬
датной почвой для программных ошибок. Более того, зачастую такие
ошибки тяжело исправлять.
Для локальных переменных и переменных уровня класса можно
использовать одинаковые имена. Следует отметить, что любой опера¬
тор объявления на уровне процедуры имеет преимущество перед ана¬
логичным на уровне класса, поэтому такие переменные будут локаль¬
ными, а для обращения к переменным уровня класса необходимо бу¬
дет использовать ключевое слово this.
Рассмотренные области действия переменных справедливы и для
других объявляемых данных (констант, пользовательских типов дан¬
ных, массивов и др.).
Для описания переменных в языке С# используются следующие
модификаторы доступа (модификаторы видимости):
- public - поля, свойства и методы являются общедоступными;
- private - поля, свойства и методы будут доступны только
в классе, в котором они определены;
- protected - поля, свойства и методы будут доступны как в
классе, в котором они определены, так и в любом производ¬
ном класса;
- internal - поля, свойства и методы будут доступны во всех
классах внутри сборки, в которой определен класс.
2.5 Операции и выражения
В зависимости от данных и используемых операций выражения
можно разделить на арифметические, логические и символьные.
В общем виде выражение можно определить следующим образом:
операнд [знакОперации операнд] [знакОперации
операнд] ...
Где в зависимости от типа выражения используются соответ¬
ствующие операнды и знаки операций.
53
Например, a + 2 - это выражение, в котором + является знаком
операции, а а и 2 - операндами. Пробелы внутри знака операции, со¬
стоящей из нескольких символов, не допускаются. Операции C# при¬
ведены в таблице 2.6.
Операции в выражении выполняются в определенном порядке
в соответствии с приоритетами, как и в математике. В таблице 2.6
операции расположены по убыванию приоритетов, уровни приорите¬
тов разделены в таблице горизонтальными линиями.
Результат вычисления выражения характеризуется значением и
типом. Например, пусть аиЬ - переменные целого типа и описаны
так:
int а=2, Ь=5;
Таблица 2.6 - Операции C#
Категория
Знак
операции
Название
1
2
3
Первичные
x()
Вызов метода или делегата
x[]
Доступ к элементу
x++
Постфиксный инкремент
x--
Постфиксный декремент
new
Выделение памяти
typeof
Получение типа
checked
Проверяемый код
unchecked
Непроверяемый код
Унарные
+
Унарный плюс
-
Унарный минус (арифметическое отрицание)
!
Логическое отрицание
~
Поразрядное отрицание
++x
Префиксный инкремент
--x
Префиксный декремент
(тип)х
Преобразование типа
Мультипликативные
(типа умножения)
*
Умножение
/
Деление
%
Остаток от деления
Аддитивные
(типа сложения)
+
Сложение
-
Вычитание
Сдвига
<<
Сдвиг влево
>>
Сдвиг вправо
54
Окончание таблицы 2.6
1
2
3
<
Меньше
>
Больше
Отношения
<=
Меньше или равно
и проверки типа
>=
Больше или равно
is
Проверка принадлежности типу
as
Приведение типа
Проверки
==
Равно
на равенство
!=
Не равно
Поразрядные
логические
&
Поразрядная конъюнкция (И)
Л
Поразрядное исключающее ИЛИ
|
Поразрядная дизъюнкция (ИЛИ)
Условные
&&
Логическое И
логические
||
Логическое ИЛИ
Условная
? .
Условная операция
=
Присваивание
*=
Умножение с присваиванием
Присваивания
/=
Деление с присваиванием
%=
Остаток от деления с присваиванием
+=
Сложение с присваиванием
-=
Вычитание с присваиванием
Тогда выражение a + b имеет значение 7 и тип int, а выражение
a = b имеет значение, равное помещенному в переменную а (в данном
случае -5)и тип, совпадающий с типом этой переменной.
Если в одном выражении соседствует несколько операций одина¬
кового приоритета, операции присваивания и условная операция вы¬
полняются справа налево, остальные - слева направо. Для изменения
порядка выполнения операций используются круглые скобки, уровень
их вложенности практически не ограничен.
Например,
а + b + с означает (а + b) +с, аа = Ь = с означает
а = (Ь = с).
55
Пример 2.5. Использования операций
//операции одного приоритета выполняются слева
//направо, но при делении будет отбрасываться
//дробная часть;
14/5*2=4;
//скобки изменяют последовательность операций
14/ (5*2)= 1;
//вычисление остатка от деления
14%5*2=8;
//корректный вариант вещественного деления с
//указанием суффикса
14 / 5f * 2 = 5.6;
Операндами выражений могут являться: константа, переменная,
элемент массива, обращение к стандартному методу, обращение
к пользовательской процедуре-функции, арифметическое выражение
в скобках.
2.5.1 Операция new
Операция new служит для создания нового объекта. Формат опе¬
рации:
new тип ( [ аргументы ] );
С помощью этой операции можно создавать объекты как ссылоч¬
ных, так и значимых типов, например,
object z = new object();
int i = new int();// то же самое, что int i = 0;
При выполнении операции new сначала выделяется необходи¬
мый объем памяти (для ссылочных типов в динамической области
памяти, для значимых - в стеке), а затем вызывается так называе¬
мый конструктор по умолчанию, то есть метод, с помощью кото¬
рого инициализируется объект. Переменной значимого типа присваи¬
вается значение по умолчанию, которое равно нулю соответствующе¬
го типа.
56
2.5.2 Операции отрицания
Арифметическое отрицание (унарный минус —) меняет знак опе¬
ранда на противоположный. Стандартная операция отрицания опре¬
делена для типов int, long, float, double и decimal. К величинам дру¬
гих типов ее можно применять, если для них возможно неявное пре¬
образование к этим типам.
Логическое отрицание (!) определено для типа bool. Результат
операции - значение false, если операнд равен true, и значение true,
если операнд равен false.
Поразрядное отрицание (~), часто называемое побитовым, инвер¬
тирует каждый разряд в двоичном представлении операнда типа int,
uint, long или ulong. Если оба операнда имеют другие целочисленные
типы (sbyte, byte, short, ushort или char), их значения преобразуются
в тип int.
2.5.3 Явное преобразование типа
Операция используется для явного преобразования величины из
одного типа в другой. Это требуется в том случае, когда неявного
преобразования не существует. При преобразовании из более длинно¬
го типа в более короткий возможна потеря информации. Формат опе¬
рации:
( тип ) выражение
Здесь тип - это имя того типа, в который осуществляется преоб¬
разование, а выражение чаще всего представляет собой имя перемен¬
ной, например,
long b = 300;
int а = (int) b; // данные не теряются
byte d = (byte) а; // данные теряются
2.5.4 Условная операция
Условная операция (? :) имеет три операнда. Ее формат:
операнд_1 ? операнд_2 : операнд_3
Первый операнд - выражение, для которого существует неявное
преобразование к логическому типу. Если результат вычисления
57
первого операнда равен true, то результатом условной операции бу¬
дет значение второго операнда, иначе - третьего операнда. Вычисля¬
ется всегда либо второй операнд, либо третий. Их тип может разли¬
чаться.
Тип результата операции зависит от типа второго и третьего опе¬
рандов. Если операнды одного типа, он и становится типом результа¬
та операции.
2.5.5 Логические выражения
Логические выражения используются в математической логике,
их также называют Булевыми выражениями, по имени математика
Дж. Буля.
Используются следующие знаки логических операций:
- ! - логическое отрицание НЕ;
- & - логическое умножение И;
- | - логическое сложение ИЛИ;
- л - исключающее ИЛИ.
Логические операции объединяют логические величины, которые
могут принимать два значения: true (Истина) или false (Ложь). Ре¬
зультат логической операции также принимает одно из двух значе¬
ний: true (Истина) или false (Ложь).
Результат логической операции определяется таблицей 2.7.
Таблица 2.7 - Результаты логических операций
Значение
Результат операции
Операнд1 (А)
Операнд1 (В)
!A
!B
A & B
A | В
A л В
true
true
false
false
true
true
false
false
true
true
false
false
true
true
true
false
false
true
false
true
true
false
false
true
true
false
false
false
та):
Приоритет выполнения операций (в порядке убывания приорите-
! & Л I
•? ? |*
58
Пример 2.6. Использование логических операций
true & !false | false
Вычисляется !false, результат - true; далее вычисляется &.
Результат - true; последним вычисляется |, результат - true.
Выражения отношения состоят из двух арифметических или сим¬
вольных выражений, объединенных знаками операций отношения:
- > - больше;
- < - меньше;
- >= - больше или равно;
- <= - меньше или равно;
- == - равно;
- != - не равно.
Выражение принимает значение или true, или false.
Пример 2.7. Использование логических операций с операндами
различных типов
3+1>3 //результат true
surName == "Иванов" //если переменная
//surName имеет значение "Иванов",
//то результат true, иначе false
"А" > "В" //результат false,
//сравниваются значения кодов
//символов, код символа "В" больше
//чем код символа "A"
Для правильного вычисления двойных неравенств необходимо запи¬
сывать их с использованием знаков логических операций. Когда арифме¬
тические данные преобразуются к логическому типу, то 0 преобразуется в
false, а другие значения преобразуются в true. При преобразовании логи¬
ческого типа к арифметическому, false превратится в 0,а true в 1.
Корректная запись двойного неравенства
нижняяГраница < имяПеременной < верхняяГраница
в языке C# будет выглядеть следующим образом:
нижняяГраница < имяПеременной & имяПеременной <
верхняяГраница
59
Например, математическая запись 23<А<543 в языке C# должна
выглядеть следующим образом 23<A && A<543 (если использовать ||
вместо &&, то вычисление также будет некорректно).
2.5.6 Символьные выражения
В C# определены следующие операции с символьными данными:
- присваивание (=);
- проверка на равенство (==);
- проверка на неравенство (!=);
- обращение по индексу ([]);
- сцепление (конкатенация) строк (+).
Операндами символьного выражения могут быть:
- символьная константа;
- символьная переменная;
- элемент символьного массива (string);
- обращение к функции, возвращающей символьное значение.
Пример 2.8. Использование символьных выражений
string Name = "Иван";
string SurName = "Иванов";
Name + SurName; //результатом будет "ИванИванов"
Следует обратить внимание, что необходимые пробелы нужно
расставлять самостоятельно. C# их не вставляет.
2.6 Стандартные сущности
В C# имеется широкий набор встроенных (стандартных) сущно¬
стей, использование которых облегчает написание программ. Наибо¬
лее часто применяемые сущности можно разделить по функциям, ко¬
торые они выполняют:
- математические функции;
- функции проверки типов;
- функции преобразования форматов;
- функции обработки строк;
60
- функции времени и даты;
- финансовые функции.
Встроенные функции различаются тем, что некоторые возвраща¬
ют вычисленное значение, другие не возвращают. Обращение к
функциям, которые возвращают вычисленное значение, могут являть¬
ся операндом выражения.
Пример 2.9. Использование математических функций
A[i,j+l]*(Math.Cos(B+3.5)+2*Math.Pow(K,
3)) + (Math.PI-3.25) ;
//операнд Cos(B+3.5) является обращением к
//встроенной функции вычисления косинуса угла.
Обращение к встроенной функции, возвращающей значение того
или иного типа, должно соответствовать выражению, в котором к ней
обращаются. Например, в арифметическом выражении можно обра¬
щаться к функциям, возвращающим значения арифметических типов,
в символьном - символьного типа.
Обращение к функциям, которые не возвращают вычисленное
значение, являются отдельными операторами программы.
Для обращения к некоторым встроенным функциям нужно зада¬
вать значение аргумента (например, Sin(X+2), где Х+2 - выражение,
определяющее значение аргумента). Для других встроенных функций
аргумент задавать не нужно (например, ToString(), которая преобра¬
зует в строку).
2.6.1 Математические функции
В C# большой список математических функций, которые позво¬
ляют выполнять любые вычисления (табл. 2.8).
Пример 2.10. Применение математических функций
Введение операндов X и Y осуществляется через текстовые поля.
Результат вычислений отображается в элементе управления Label.
Внешний вид формы и результаты тестирования приложения приве¬
дены на рисунке 2.4.
61
Таблица 2.8 - Математические функции
Имя
Описание
Результат
Пояснение
Abs
Модуль
Перегружен
|x| записывается как Abs(x)
Acos
Арккосинус
double
Acos(double x)
Asm
Арксинус
double
Asin(double x)
Atan
Арктангенс
double
Atan2(double x, double y) - угол,
тангенс которого есть результат
деления у нах
BigMul
Произведение
long
BigMul(int x, int y)
Ceiling
Округление
до большего целого
double
Ceiling(double х)
Cos
Косинус
double
Cos(double x)
Cosh
Гиперболический
косинус
double
Cosh(double x)
DivRem
Деление и остаток
Перегружен
DivRem(x, y, rem)
E
База натурального
логарифма (число е)
double
2,71828182845905
Exp
Экспонента
double
e1 записывается как Exp(x)
Floor
Округление
до меньшего целого
double
Floor(double x)
Log
Натуральный логарифм
double
logex записывается как Log(x)
Log10
Десятичный логарифм
double
logiox записывается как Log10(x)
Max
Максимум из двух чисел
Перегружен
Max(x, y)
Min
Минимум из двух чисел
Перегружен
Min(x, y)
PI
Значение числа п
double
3,14159265358979
Pow
Возведение в степень
double
xy записывается как Pow(x, y)
Round
Округление
Перегружен
Round(3.1) даст в результате 3.
Round(3.8) даст в результате 4
Sign
Знак числа
int
Аргументы перегружены
Sin
Синус
double
Sin(double x)
Sinh
Гиперболический синус
double
Sinh(double x)
Sqrt
Квадратный корень
double
tx записывается как Sqrt(x)
Tan
Тангенс
double
Tan(double x)
private void buttonl_Click(object sender,
EventArgs e)
{
double x,y;
x = double.Parse(textBoxl.Text);
у = double.Parse(textBox2.Text);
label3.Visible = true;
label3.Text = "Максимум из x и y : " +
Math.Max(x, y);
label4.Visible = true;
double z = Math.Pow(Math.Sin(x), 2) +
Math.Pow(Math.Sin(y), 2);
label4.Text = "Сумма квадратов синусов x и у
: " + z;}
62
Рисунок 2.4 - Результат работы программы
2.6.2 Структура времени и даты
Для работы со временем и датами в C# используется структура
DateTime. Она представляет дату и время от 00:00:00 1 января 0001
года до 23:59:59 31 декабря 9999 года. Основные члены указанной
структуры приведены в таблице 2.9.
Таблица 2.9 - Основные члены структуры DateTime
Функция
Возвращаемое значение
Today
Возвращает текущую системную дату
UtcNow
Возвращает текущие дату и время относительно времени по
Гринвичу (GMT)
Now
Возвращает текущую дату и время по системному календарю
и часам компьютера
Add
Добавляет к дате указанное значение. Синтаксис:
Add(TimeSpan value)
AddDays
Добавляет к текущей дате несколько дней. Синтаксис:
AddDays(double value)
AddHours
Добавляет к текущей дате несколько часов. Синтаксис:
AddHours(double value)
AddMinutes
Добавляет к текущей дате несколько минут. Синтаксис:
AddMinutes(double value)
AddMonths
Добавляет к текущей дате несколько месяцев. Синтаксис:
AddMonths(int value)
AddYears
Добавляет к текущей дате несколько лет. Синтаксис:
AddYears(int value)
Substract
Возвращает количество временных интервалов между двумя
датами.
Синтаксис:
Substract(DateTime date)
ToLocalTime
Преобразует время UTC в локальное время, добавляя
смещение относительно времени по Гринвичу
ToUniversalTime
Преобразует локальное время во время UTC, то есть
вычитает смещение относительно времени по Гринвичу
63
2.6.3 Преобразование форматов
Чтобы отформатировать выражение в специфическом формате,
необходимо использовать метод Format.
Для форматирования строк в C# используется метод Format, ко¬
торый заменяет все вхождения параметров в фигурных скобках зна¬
чениями соответствующих переменных из списка вывода. После но¬
мера параметра можно задать минимальную ширину поля вывода,
а также указать спецификатор формата, который определяет форму
представления выводимого значения.
В общем виде параметр задается следующим образом:
{п [,т[:спецификаторФормата]]}
где n - номер параметра. Параметры нумеруются с нуля, нулевой па¬
раметр заменяется значением первой переменной из списка вывода,
первый параметр - второй переменной, ит.д.;
m - определяет минимальную ширину поля, которое отводится под
выводимое значение. Если выводимому числу достаточно меньшего ко¬
личества позиций, неиспользуемые позиции заполняются пробелами.
Если числу требуется больше позиций, параметр игнорируется;
спецификаторФормата - определяет формат вывода значения.
Основные спецификаторы формата приведены в таблице 2.10.
Таблица 2.10 - Спецификаторы форматирования
Спецификатор
Описание
C или c
Задает формат денежной единицы, указывает количество
десятичных разрядов после запятой
D или d
Целочисленный формат, указывает минимальное количество цифр
E или e
Экспоненциальное представление числа, указывает количество
десятичных разрядов после запятой
F или f
Формат дробных чисел с фиксированной точкой, указывает
количество десятичных разрядов после запятой
G или g
Задает более короткий из двух форматов: F или E
N или n
Также задает формат дробных чисел с фиксированной точкой,
определяет количество разрядов после запятой
P или p
Задает отображения знака процентов рядом с число, указывает
количество десятичных разрядов после запятой
X или x
Шестнадцатеричный формат числа
64
Пример 2.11. Использование различных спецификаций формата
public void TestFormat()
{
//метод Format
int x = 77;
string s = string.Format("x = {0}",x);
labell.Text = s;
s = string.Format("MToro: {0,10} p.",x);
label2.Text = s;
s = string.Format("HToro: {0,6:######} p.",
x);
label3.Text = s;
s = string.Format("HToro: {0:P} ",0.77);
label4.Text = s;
s = string.Format("MToro: {0,4:C}
",77.77);
label5.Text = s;
//Национальные особенности
System.Globalization.Culturelnfo ci = new
System.Globalization.CultureInfo("en-US");
s = string.Format(ci,"MToro: {0,4:C}
",77.77);
label6.Text = s;
}//TestFormat
В примере показано использование различных спецификаций
формата с разным числом параметров и разными кодами форматиро¬
вания.
В частности, показан вывод процентов и
валют. В последнем примере с валютами де¬
монстрируется задание провайдером нацио¬
нальных особенностей. С этой целью созда¬
ется объект класса CultureInfo, инициализи¬
рованный так, чтобы он задавал особенности
форматирования, принятые в США. Заметьте,
класс CultureInfo наследует интерфейс
IFormatProvider. Российские национальные
особенности форматирования установлены
по умолчанию. Результат работы программы
приведен на рисунке 2.5.
ITTffWl ,1п1 х|
х=77
Итого: 77р
Итого: 77р
Итого: 77.00%
Итого: 77.77р
Итого: $77.77
Рисунок 2.5 -
Результаты работы
метода Format
65
Метод ToString() не только возвращает стандартное строковое
описание объекта, но и может осуществлять форматирование. Он
поддерживает те же спецификаторы, которые используются в методе
Format.
Для форматирования вывода дат и времени применяются форма¬
ты, приведенные в таблице 2.11.
Таблица 2.11 - Форматирование дат и времени
Описатель
Описание
D
Полный формат даты. Например, 17 июля 2015 г.
d
Краткий формат даты. Например, 17.07.2015
F
Полный формат даты и времени. Например, 17 июля 2015 г. 17:04:43
f
Полный формат даты и краткий формат времени.
Например, 17 июля 2015 г. 17:04
G
Краткий формат даты и полный формат времени.
Например, 17.07.2015 17:04:43
g
Краткий формат даты и времени. Например, 17.07.2015 17:04
M, m
Формат дней месяца. Например, 17 июля
O, o
Формат обратного преобразования даты и времени.
Вывод даты и времени в соответствии со стандартом ISO 8601
в формате "yyyy'-'MM'-'dd'T'HH':'mm':'ssVfffffffzzz".
Например, 2015-07-17T17:04:43.4092892+03:00
R, r
Время по Гринвичу. Например, Fri, 17 Jul 2015 17:04:43 GMT
s
Сортируемый формат даты и времени. Например, 2015-07-
17T17:04:43
T
Полный формат времени. Например, 17:04:43
t
Краткий формат времени. Например, 17:04
U
Универсальный полный формат даты и времени.
Например, 17 июля 2015 г. 17:04:43
u
Универсальный сортируемый формат даты и времени.
Например, 2015-07-17 17:04:43Z
Y, y
Формат года. Например, Июль 2015
2.6.4 Пользовательские форматы
Пользовательские форматы позволяют определить способ фор¬
матирования числовых данных. При построении пользовательского
формата можно использовать символы, которые приведены в табли¬
це 2.12.
66
Таблица 2.12 - Символы, которые используются
в пользовательских форматах
Символ
Описание
0
Резервирует позицию цифрового разряда. Отображает цифру или ноль.
Если у числа, представленного параметром, есть какая-нибудь цифра
в той позиции разряда, в которой в строке формата находится «0»,
функция отражает эту цифру параметра, если нет - в этой позиции
отображается ноль
#
Резервирует позицию цифрового разряда. Отображает цифру или
пустое место. Если у числа, представленного параметром, есть
какая-нибудь цифра в той позиции разряда, в которой в строке формата
находится «#», функция отображает эту цифру параметра, если нет -
в позиции не отображается ничего (Действие этого символа подобно
действию «0», за исключением того, что начальные и завершающие
нули не отображаются)
Резервирует позицию цифрового разряда. Указание точки в строке
формата определяет, сколько разрядов необходимо отображать слева
и справа от десятичной точки
%
Резервирует процентное отображение числа
Разделитель разряда сотен от тысяч
Разделитель часов, минут и секунд в категории форматов времени
/
Разделитель дня, месяца и года в категории форматов даты
E+, E-,
e+, e-
Разделитель мантиссы и порядка в экспоненциальном формате
Ряд примеров результатов действия пользовательских форматов
приведен в таблице 2.13.
Таблица 2.13 - Примеры пользовательских форматов
Формат
Результат
Format("{0:##.###}", Math.Pow(1.2, 2))
1.44
Format("{0:##.000}", Math.Pow(1.2, 2))
1.440
Format("{0:#.###e+##}", Math.Sin(l) * Math.Exp(5))
124,885e+37
2.6.5 Методы обработки строк
В C# существуют следующие методы обработки строковых
выражений (табл. 2.14).
67
Таблица 2.14 - Методы обработки строк
Метод
Возвращаемое значение
1
2
Compare
Возвращает результат сравнения двух строк.
Синтаксис:
Compare (stringl, string2 [, comparisonType])
- string1 и string2 - два любых строковых выражения;
- comparisonType - указывает способ сравнения строк.
Допустимые значения соответствуют перечислению StringComparison.
Наиболее часто применяющиеся значения: Ordinal (4) - двоичное
сравнение и OrdinalIgnoreCase (5) - двоичное сравнение без учета
регистра.
Значение, которое возвращает функция:
- если string1 меньше чем string2, то-1;
- если string1 равняется string2, то 0;
- если string1 больше чем string2, то 1
Concat
Соединяет строки в одну строку
Copy
Создание копии строки
Format
Форматирование в соответствии с заданными спецификаторами
формата
Insert
Используется для вставки одной строки в другую.
Синтаксис:
Insert([startlndex, JsubString)
- subString - вставляемая подстрока;
- startIndex - номер символа в текущей строке, с которого
будет осуществляться вставка
IndexOf,
IndexOfAny,
LastIndexOf,
LastIndexOfAny
Определение индексов первого и последнего вхождения заданной
подстроки или любого символа из заданного набора
Преобразует массив в строку.
Синтаксис:
Join
Join(SourceArray[, Delimiter])
- SourсеАrray - массив, который преобразуется;
- Delimiter - разделитель между элементами строкового
выражения, из которых создается массив. По умолчанию ис¬
пользуется пробел.
Например,
massiv = ("Зима", "Весна", "Лето", "Осень"};
stroka = Join(massiv, ",")
В результате будет получена строка "Зима, Весна, Лето, Осень"
Length
Длина строки (количество символов).
Позволяет дополнить строку символами слева.
Синтаксис:
PadLeft
PadLeft(totalWidth[, paddingChar])
- totalWidth - общая длина результирующей строки;
- paddingChar - символ, которым дополняется строка.
PadRight
Позволяет дополнить строку символами справа. Аналогично методу
PadLeft()
68
Окончание таблицы 2.14
1
2
Remove
Используется для удаления части строки.
Синтаксис:
Remove(startIndex[, count])
- startIndex - позиция символа в исходной строке, с которого
удалится подстрока;
- count - количество удаляемых символов. Если параметр не
указан, удаление происходит до конца строки
Replace
Используется для замены части строки.
Синтаксис:
Replace(oldValue, newValue)
Все вхождения строки oldValue в вызывающей строке заменяются
строкой newValue.
ToCharArray
Преобразование строки в массив символов.
ToLower
Преобразует символы строки к нижнему регистру.
ToUpper
Преобразует символы строки к верхнему регистру.
Возвращает копию строки без указанных символов chr в начале и
Trim
конце. Без указания параметра будут, удалятся пробелы.
Синтаксис:
Trim(chr)
Split
Преобразует строку в одномерный массив, который нумеруется с ну¬
ля.
Синтаксис:
Split(Delimiter[, Limit], Options]])
- Delimiter - разделитель между элементами строкового выра¬
жения, из которых создается массив. По умолчанию исполь¬
зуется пробел;
- Limit - максимальное количество элементов в массиве. Если
значение параметра равняется -1, то ограничений на
размерность массива нет;
- Options может принимать одно из двух значений: None - пу¬
стые строки включаются в конечный результат разделения ис¬
ходной строки, RemoveEmptyEntries - пустые строки исклю¬
чаются из конечного результата разделения исходной строки.
Например,
stroka = "Привет участникам автопробега!";
massiv = stroka.Split]' ');
for (i =0; i< massiv.Length; i++)
{
MessageBox.Show(massiv[i]);
}
Substring
Извлечение подстроки.
Синтаксис:
Substring(startlndex[, length])
- startIndex - позиция символа в исходной строке, начиная
с которого формируется подстрока;
- length - количество символов. Если параметр не указан,
извлечение происходит до конца строки
69
2.7 Операторы
Любая программа на C# состоит из последовательности операто¬
ров. Оператором (Statement) является синтаксически полное описа¬
ние конкретной команды (аналог понятия «предложение» на русском
или другом языке), которая выражает одно действие или определение.
Одному оператору соответствует одна строка программы, завер¬
шающаяся точкой с запятой. Частным случаем выражения является
пустой оператор (он используется, когда по синтаксису оператор тре¬
буется, а по смыслу - нет).
Операторы программы выполняются последовательно сверху
вниз (слева направо для операторов в одной строке), если другие опе¬
раторы (перехода, управления, обращения к функции или процедуре)
не вызывают изменения последовательности их выполнения.
Пример 2.12. Использование операторов
// выполняется операция инкремента
i++;
// выполняется умножение с присваиванием
а *=Ь+ с;
// выполняется вызов функции
funName( i, k );
// цикл из пустого оператора (бесконечный)
while ( true );
В C# блок, или составной оператор, - это последовательность
описаний и операторов, заключенная в фигурные скобки. Блок
воспринимается компилятором как один оператор и может использо¬
ваться в тех местах, где синтаксис требует одного оператора, а алго¬
ритм - нескольких. Блок может содержать один оператор или быть
пустым.
Строки программы могут быть обозначены метками. Метка ука¬
зывает на следующую строку программы. Имя метки строится по
правилам построения идентификаторов языка и заканчивается двое¬
точием. Метка может начинаться с любой позиции строки, если ей не
предшествует никакой символ.
70
Пример 2.13. Использование оператораметки
routine: //метка
//оператор, обозначенный меткой routine:
num = num / 2;
MessageBox.Show("nonoBMHa от введенного Вами
числа равняется" + num);
В данном и последующих примерах используется окно вывода
сообщения MessageBox. MessageBox представляет собой простейшее
диалоговое окно, для вызова которого используется метод Show().
Программу легче читать и отлаживать, если операторы программы
обеспечены комментариями. Строка с комментариями начинается с
символа ‘//’, после которого можно размещать любые замечания в тек¬
сте программы. Если комментарии располагаются в несколько строк,
то в первой строке нужно указать символ ‘/*’, в последней - ‘*/’.
2.7.1 Оператор присваивания
Оператор присваивания (assignment statement) имеет такой вид:
{переменная | элементМассива} = выражение
Переменной или элементу массива в левой части оператора при¬
сваивается значение вычисленного выражения в правой части.
Пример 2.14. Использование оператораприсваивания
//Переменной С присваивается значение выражения
C = A[i, j + 1] * (Math.Cos(B + 3.5) + 2 * K *
3) + (Math.PI - 3.25);
//Переменной StartTime присваивается значение,
//которое определяет свойство Now (текущая дата
//и время)
StartTime = DateTime.Now;
//увеличение значения переменной i на 1 и
//присваивание полученного значения переменной k
k = ++i;
71
//присваивание элементу массива MassivJ
//значения выражения
MassivJ[3, 4] = Math.Pow(B, 2) - 4*L*C+D;
//Используется конструктор для преобразования
//трех последовательных чисел (год, месяц,
//число) в дату
Studentl.Birthday = new DateTime(1975, б, 11);
//Переменной Р присваивается значение
//логического выражения
Р = (X + 2 >= К) && (L + В > 3) || (L * X + В *
Y == D) && (Н <=Y&&Y <= Q);
2.7.2 Условный оператор
Как правило, алгоритмы обработки информации и реализующие
их программы содержат проверки каких-то условий, от которых зави¬
сят дальнейшие действия. Для этого предназначен условный опера¬
тор, который имеет следующий вид:
if ( логическоеВыражение ) оператор1; [ else
оператор2; ]
или
if ( логическоеВыражение)
{
[блок0ператоров1] [else if
логическоеВыражение
[блок0ператоров2]] [else
[блокОператоровИ]]
}
Сначала вычисляется логическое выражение. Если оно имеет
значение true, выполняется первый оператор, иначе - второй. После
этого управление передается на оператор, следующий за услов¬
ным. Ветвь else может отсутствовать. Если в какой-либо ветви требу¬
ется выполнить несколько операторов, их необходимо заключить в
блок. Блок может содержать любые операторы, в том числе описания
и другие условные операторы, но не может состоять из одних описа¬
ний.
72
Пример 2.15. Условные операторы
//Выражение 1
if(a<0)b=l;
//Выражение 2
if (a<b&& (a>d|| а==0) )
Ь++;
else
{
b *= а;
а = 0;
}
//Выражение 3
if (a<b )
if (а <с)
т = а;
else
т=с;
else
if (b<c)
m = b;
else
m=c;
//Выражение 4
if (b>a) max = b; else max = a;
Если требуется проверить несколько условий, их объединяют
знаками логических условных операций. Например, выражение 2
в примере будет истинно в том случае, если выполнится одновремен¬
но условие a < b и одно из условий в скобках. Выражение 3 в примере
вычисляет наибольшее значение из трех переменных. Следует отме¬
тить, что компилятор относит часть else к ближайшему ключевому
слову if.
Первая синтаксическая конструкция условного оператора обес¬
печивает альтернативное выполнение первого оператора или второго
оператора в зависимости от значения логического выражения (при¬
нимает значение true или false).
73
if ( true ) //этот оператор выполнится
else //этот оператор не выполнится
//следующий оператор
if ( false ) //этот оператор не выполнится
else //этот оператор выполнится
//следующий оператор
Вторая синтаксическая конструкция условного оператора обес¬
печивает альтернативное выполнение блоков операторов (блокОпера-
торов1, блокОператоров2, блокОператоровК) в зависимости
от значений логических выражений (принимает значение true или
false).
if ( true )
{
//эти операторы блока выполняются
}
else
{
//эти операторы блока не выполняются
}
//следующий оператор
if ( false )
{
//эти операторы блока не выполняются
}
else
{
//эти операторы блока выполняются
}
//следующий оператор
Пример 2.16. Подсчет количества очков после выстрела по ми¬
шени
Для ввода значений точки выстрела используется два элемента
textBox. Имитация выстрела осуществляется нажатием на кнопку
«Выстрел». Результат начисления баллов в зависимости от расстояния
до центра отображается в элементе label (рис. 2.6).
74
sender
private void buttonl_Click(object
EventArgs e)
{
double x = double.Parse(textBoxl.Text);
double у = double.Parse(textBox2.Text);
int num = 0;
if (x*x+y*y<l) num = 2;
else if (x * x + у * y< 4) num = 1;
label3.Visible = true;
1аЬе13.Техк="Результат ="+num+" очков";
}
Рисунок 2.6 - Результаты работы программы
Пример 2.17. Использование условного оператора
if (answer == "Нет")
{
//если ответ неверный, то оценка уменьшается
//на единицу
mark -= 1;
}
else
{
//в противном случае
if (num_answer == mark_num)
{
//если номер вопроса равняется
//указанному, то осуществляется переход
//на другую тему
75
++topic;
}
else
{
//иначе определяется результирующая
//оценка
result = mark;
}
}
Пример 2.18. Определение количества десятичных цифр
Программа должна определять количество десятичных цифр во
введенном целом числе от 0 до 1000.
private void buttonl_Click(object sender,
EventArgs e)
{
//описание переменных
int y;
string unit;
int x = int.Parse(textBoxl.Text);
if (x < 10)
{ //если X < 10, то в числе 1 цифра,
y = 1;
}
else
{
if (x < 100)
{
//иначе, если X< 100 в числе 2
//цифры
У = 2;
}
else
{
//иначе 3 цифры
У = 3;
}
}
76
//Определение правильного склонения в
//предложении
if (у > 1) unit = " цифры."; else unit = "
цифру.";
//Вывод ответа
MessageBox.Show("BBefleHHoe число имеет " + у
+ unit);
}
После запуска программы появится форма, в которой можно
набрать число и ввести его щелчком мыши по кнопке "Ok" или
нажимая клавишу <Enter> на клавиатуре (рис. 2.7). После ввода по¬
явится окно с результатом (рис. 2.8).
Рисунок 2.7 - Окно ввода числа
Рисунок 2.8 - Результат работы программы
2.7.3 Управляющая структура switch
Структура switch применяется, когда одна величина принимает
участие в нескольких логических сравнениях и определяет, какой блок
операторов будет выполняться. Алгоритм такого множественного срав¬
нения можно запрограммировать с использованием логического струк¬
турного оператора, но использование структуры switch эффективнее.
Чаще всего структура switch применяется в тех случаях, когда
сравниваемая величина является целым числом. Например, для пере¬
77
хода к блоку операторов программы в зависимости от значения пара¬
метра, выбранного пользователем в диалоге.
Структура switch имеет следующий синтаксис:
switch (выражениеКотороеПроверяется){
case списокВыражений1: [ блокОператоров1 ]
case списокВыражений2: [ блокОператоров2 ]
case списокВыраженийЫ: [ блокОператоровЫ ]
[ default: операторы ]
}
Выполнение оператора начинается с вычисления выражения. Тип
выражения чаще всего целочисленный (включая char) или строковый.
Затем управление передается первому оператору из списка, помечен¬
ному константным выражением, значение которого совпало с вычис¬
ленным. Если совпадения не произошло, выполняются операторы,
расположенные после слова default, а при его отсутствии управление
передается следующему за switch оператору.
Для того, чтобы не выполнялась следующая ветвь переключате¬
ля, текущая должна заканчиваться явным оператором перехода,
а именно одним из операторов break, goto или return.
Пример 2.19. Использование управляющей структуры switch
switch ( value )
{
case 1:
case 3:
//блокОператоров1
break;
case 12:
//блокОператоров2
break;
default:
//блокОператоровЭ
break;
}
В данном примере проверяемым выражением является значение
value. Если значение value 1 или 3 (case 1: case 3), выполняется бло-
78
кОператоров1. Если значение value соответствует 12, выполняется
блокОператоров2. Если значение value не равняется ни одному из
указанных значений, выполняется блокОператоровЗ.
Пример 2.20. Реализация простейшего калькулятора на четыре
действия
Для ввода операндов и одной из четырех операций используются
элементы управления textBox. Результат выполнения соответствую¬
щей операции выводится после нажатия кнопки «Посчитать» в эле¬
мент управления Label (рис. 2.9)
private void buttonl_Click_l(object sender,
EventArgs e)
{
double res;
double a = double.Parse(textBoxl.Text);
double b = double.Parse(textBox3.Text);
char op = char.Parse(textBox2.Text);
bool ok = true;
switch (op)
{
case
: res
= a
+
b;
break;
case
? _ ?
: res
= a
-
b;
break;
case
»*»
: res
= a
*
b;
break;
case
: res
= a
/
b;
break;
default:
res =
double.
NaN; ok
}
label3.Visible = true;
if (ok) label3.Text = "Результат: " + res;
else label3.Text = "Недопустимая операция";
}
Рисунок 2.9 - Результат работы программы
79
2.7.4 Операторы передачи управления
В С# выделяют пять операторов, изменяющих естественный по¬
рядок выполнения программного кода:
1) оператор безусловного перехода goto;
2) оператор выхода из цикла break;
3) оператор перехода к следующей итерации цикла continue;
4) оператор возврата из функции return;
5) оператор генерации исключения throw.
Эти операторы могут передать управление как в пределах блока,
в котором они использованы, так и за его пределы. Передача управле¬
ния внутрь другого блока запрещена.
Оператор безусловного перехода goto используется в одной
из трех форм.
1. Передает управление на помеченный оператор. Синтаксис:
goto метка;
При этом в теле функции должна присутствовать конструкция вида:
метка: оператор;
Метка - это идентификатор, областью видимости которого явля¬
ется функция, в теле которой он задан. Метка должна находиться
в той же области видимости, что и оператор перехода.
2. Передает управление на соответствующую константному вы¬
ражению ветвь в операторе выбора switch. Синтаксис:
goto case константноеВыражение;
3. Передает управление на ветвь default в операторе выбора
switch. Синтаксис:
goto default;
Оператор break используется внутри операторов цикла или вы¬
бора для перехода в точку программы, находящуюся непосредственно
за оператором, внутри которого находится оператор break.
Оператор перехода к следующей итерации текущего цикла
continue пропускает все операторы, оставшиеся до конца тела цикла,
и передает управление на начало следующей итерации.
80
Оператор возврата из функции return завершает выполнение функ¬
ции и передает управление в точку ее вызова. Синтаксис оператора:
return [ выражение ];
Тип выражения должен иметь неявное преобразование к типу
функции. Если тип возвращаемого функцией значения описан как
void, выражение должно отсутствовать.
2.8 Массивы
Массивом является набор переменных одного типа с одним име¬
нем и различными индексами. Каждая такая переменная называется
элементом массива. Количество элементов, хранящихся в массиве,
называется размером массива.
Массив в С# относится к ссылочным типам данных, то есть рас¬
полагается в динамической области памяти, поэтому создание масси¬
ва начинается с выделения памяти под его элементы. Элементами
массива могут быть величины как значимых, так и ссылочных типов
(в том числе массивы). Массив значимых типов хранит значения, мас¬
сив ссылочных типов - ссылки на элементы. Всем элементам при со¬
здании массива присваиваются значения по умолчанию: нули для
значимых типов и null для ссылочных.
На рисунке 2.10 представлен массив, состоящий из пяти элемен¬
тов любого значимого типа, например, int или double, а рисунок 2.11
иллюстрирует организацию массива из элементов ссылочного типа.
Рисунок 2.10 - Простые переменные и массив
из элементов значимого типа
81
Рисунок 2.11 - Массив из элементов ссылочного типа
Операторы создания массива из 10 целых чисел и массива из
100 строк:
int[] w = new int[10];
string[] z = new string[100];
В первом операторе описан массив w типа int[]. Операция new
выделяет память под 10 целых элементов, и они заполняются нулями.
Во втором операторе описан массив z типа string[]. Операция
new выделяет память под 100 ссылок на строки, и эти ссылки запол¬
няются значением null. Память под сами строки, составляющие мас¬
сив, не выделяется - это будет необходимо сделать перед заполнени¬
ем массива.
Количество элементов в массиве (размерность) не является ча¬
стью его типа, оно задается при выделении памяти и не может быть
изменено впоследствии. Размерность может задаваться не только кон¬
стантой, но и выражением. Результат вычисления этого выражения
должен быть неотрицательным, а его тип должен иметь неявное пре¬
образование к int, uint, long или ulong.
Элементы массива нумеруются с нуля, поэтому максимальный
номер элемента всегда на единицу меньше размерности. Для обраще¬
ния к элементу массива после имени массива указывается номер эле¬
мента в квадратных скобках, например,
w[4] z[i]
82
С элементом массива можно делать все, что допустимо для пере¬
менных того же типа.
Массивы одного типа можно присваивать друг другу. При этом
происходит присваивание ссылок, а не элементов, как и для любого
другого объекта ссылочного типа, например,
int[] а = new int[10];
int[] b=a; //Ьиа указывают на один и тот
// же массив
В C# существуют три разновидности массивов: одномерные,
прямоугольные и ступенчатые (невыровненные).
2.8.1 Одномерные массивы
При построении графических интерфейсов пользователей чаще
всего используются одномерные массивы. Варианты их описания
вС#:
тип[.
имя;
тип['
имя =
new
тип
[ размерность ];
тмп[\
имя =
{ список
инициализаторов };
тмп[\
имя =
new
тип
[] { список инициализаторов
тмп[\
имя =
new
тип
[ размерность ] {
}
список_инициализаторов };
Пример 2.21. Описания одномерных массивов
// 1 элементов нет
int[] а;
// 2 элементы равны 0
int[] b = new int[4];
// 3 new подразумевается
int[] с={61, 2, 5, -9 };
// 4 размерность вычисляется
int[] d = new int[] { 61, 2, 5,
// 5 избыточное описание
int[] е = new int[4] { 61, 2, 5,
-9 };
-9 };
83
В примере описано пять массивов. Отличие первого оператора от
остальных состоит в том, что в нем фактически описана только ссыл¬
ка на массив, а память под элементы массива не выделена.
В каждом из остальных массивов по четыре элемента целого типа.
Как видно из операторов 3-5, массив при описании можно инициали¬
зировать. Если при этом не задана размерность (оператор 3), количе¬
ство элементов вычисляется по количеству инициализирующих значе¬
ний. Операцию new можно опускать, тогда она будет выполнена по
умолчанию (оператор 3). Если присутствует и размерность, и список
инициализаторов, размерность должна быть константой (оператор 5).
2.8.2 Прямоугольные массивы
Прямоугольный массив имеет более одного измерения. Варианты
описания двумерного массива:
типО]
тип[,]
имя;
имя =
new
тип[
разм 1, разм 2 ];
тип[,]
имя =
{ список
инициализаторов };
тип[,]
имя =
new
тип
Г,] {
список_инициализаторов };
тип[,] имя = new тип [ разм_1, разм_2 ] {
список_инициализаторов };
Пример 2.22. Описания двумерных массивов
// 1 элементов нет
int [,] а;
// 2 элементы равны 0
int[,] b = new int[2, 3];
// 3 new подразумевается
int[,] с={{1, 2, 3}, {4, 5, 6}};
// 4 размерность вычисляется
int[,] с = new int[,] {{1, 2, 3}, {4, 5, 6}};
// 5 избыточное описание
int[,] d = new int[2,3] {{1, 2, 3}, {4, 5, 6}};
К элементу двумерного массива обращаются, указывая номера
строки и столбца, на пересечении которых он расположен, например,
а[1, 4] b[i, j] b[j, i]
84
2.8.3 Ступенчатые массивы
В ступенчатых массивах количество элементов в разных строках
может различаться. В памяти ступенчатый массив хранится иначе,
чем прямоугольный: в виде нескольких внутренних массивов, каждый
из которых имеет свой размер. Кроме того, выделяется отдельная об¬
ласть памяти для хранения ссылок на каждый из внутренних массивов
(рис. 2.12).
Рисунок 2.12 - Ступенчатый массив C#
Пример 2.23. Объявление ступенчатого массива
//Объявляем 2-мерный ступенчатый массив
int[][] k = new int[2][];
//Объявляем 0-й элемент ступенчатого массива -
//это массив, содержащий 3 элемента
k[0] = new int[3];
//Объявляем 1-й элемент ступенчатого массива -
//это массив, содержащий 4 элемента
к[1] = new int[4];
//записываем 22 в последний элемент массива
к[1][3] = 22;
85
Пример 2.24. Перестановка элементов массива
Как пример рассмотрим фрагмент программы, которая реализует
перестановку элементов массива massivA, состоящего из 10 элемен¬
тов, в обратном порядке.
//Объявление массива и вспомогательного элемента
float[] massivA = new float[10];
float reserve;
int i = 0;
//Перестановка элементов массива в обратном
//порядке
repeat: reserve = massivA[i];
massivA[i] = massivA[massivA.Length - i -
1];
massivA[massivA.Length - i - 1]= reserve;
++i;
if (i <= massivA.Length / 2)
{
//повтор действий до тех пор, пока
//не достигнута середина массива
goto repeat;
}
В данном примере три оператора перестановки элементов, опера¬
торы изменения значения индекса и проверки условия выполняются
несколько раз при разных значениях i (изменяемый параметр). Реали¬
зован так называемый «ручной» цикл, т. е. присутствуют операторы
задания начального значения параметра, изменения значения пара¬
метра, проверки условия выхода параметра за заданную границу, ко¬
торые и организуют цикл вычислений.
Следует отметить, что использование «ручных циклов» и опера¬
тора goto при разработке приложений нежелательно, так как ухудша¬
ет удобочитаемость программного кода. Вместо указанных операто¬
ров, повторяемые действия рекомендуется организовывать в циклы.
86
2.8.4 Класс System.Array
Все массивы в C# построены на основе базового класса Array,
который содержит свойства и методы. Наиболее часто используемые
из них, приведены в таблице 2.15.
Использование элементов класса Array при написании про¬
граммного кода, позволяет как сократить количество строк, так и
ускорить выполнение расчетов при работе с большими массивами
данных.
Таблица 2.15 - Некоторые элементы класса Array
Элемент
Описание
Length
Количество элементов массива (по всем размерностям)
BinarySearch
Двоичный поиск в отсортированном массиве
Clear
Присваивание элементам массива значений по умолчанию
c°py
Копирование заданного диапазона элементов одного массива
в другой массив
GetValue
Получение значения элемента массива
IndexOf
Поиск первого вхождения элемента в одномерный массив
Resize
Изменение количества элементов в массиве до указанной
величины
Reverse
Изменение порядка следования элементов на обратный
Sort
Упорядочивание элементов одномерного массива
Перестановка элементов массива из примера 2.24 с использова¬
нием элементов класса Array реализуется с помощью одной строчки
кода:
Array.Reverse(massivA);
2.9 Циклы
В алгоритмах обработки информации и реализующих их про¬
граммах широко используются циклы - повторяющиеся одинаковые
вычисления.
Для реализации такого рода программ в C# имеются специальные
средства - операторы цикла.
87
2.9.1 Цикл с параметром for
Синтаксис оператора следующий:
for ( инициализация; выражение; модификации )
оператор;
Инициализация служит для объявления величин, используемых
в цикле, и присвоения им начальных значений. В этой части можно
записать несколько операторов, разделенных запятой, например,
for ( int i=0, j=20; ...
int k, m;
for ( k= 1, m= 0; ...
Областью действия переменных, объявленных в части инициали¬
зации цикла, является цикл.
Выражение типа bool определяет условие выполнения цикла: ес¬
ли его результат равен true, цикл выполняется.
Модификации выполняются после каждой итерации цикла
и служат обычно для изменения параметров цикла или шага цикла.
В части модификаций можно записать несколько операторов через
запятую, например,
for ( int i = 0, j = 20; i < 5 && j > 10; i + + ,
j-- ) •••
Простой или составной оператор представляет собой тело цикла.
Любая из частей оператора for может быть опущена, но соответству¬
ющие части точки с запятой должны оставаться.
Пример 2.25. Определение максимального значения в массиве
Фрагмент программы определяет максимальное значение эле¬
ментов одномерного массива из вещественных элементов.
//объявление массива вещественных чисел и его
//максимального элемента
doublet] massivB = {-5.7, 24, 50, 18, 3, 16, -7,
9, -1, 3.4, 0.012 };
double maxB;
88
//выбор в качестве максимального первого
//элемента массива
maxB = massivB[0];
//определение максимального элемента массива
for (int i=l; i< massivB.Length; i++)
{
if (massivB[i] > maxB)
{
maxB = massivB[i];
}
}
MessageBox.Show("MaKCHMaabHoe значение из
массива: " + maxB);
Для вывода результата используется диалоговое окно MessageBox.
При использовании оператора цикла необходимо соблюдать пра¬
вила:
1) следует избегать изменения значения параметра цикла в каких-
либо операторах внутри цикла;
2) передача управления на операторы внутри цикла (кроме пер¬
вого) из каких-либо операторов вне цикла запрещена.
Можно использовать вложенные циклы. При выполнении цикла в
цикле внутренний цикл выполняется для каждого значения параметра
внешнего цикла.
Внутренний ("вложенный") цикл должен целиком содержаться во
внешнем цикле. В C# количество вложенных циклов не ограничено.
Пример 2.26. Формирование вектора из массива
Фрагмент программы для формирования вектора massivA[5], эле¬
ментами которого являются суммы столбцов матрицы massivB[5, 4].
//объявление одномерного и двумерного массивов
doublet] massivA = new double[5];
doublet,] massivB = new double[5, 4];
//открытие цикла по элементам массива А
//и по столбцам массива В
for (int j=0;j< massivA.Length; j++)
89
{
//открытие цикла по строкам массива В
for (int i=0; i< massivB.Length; i++)
{
//определение элемента массива А как
//суммы элементов столбца матрицы В
massivA[i] += massivB[i, j];
}
}
Пример 2.27. Массив элементов пользовательского класса
На основании пользовательского класса определен массив для
хранения результатов экзаменов студентов Result[5] session.
class Result
{
public string surname;
public string[] nameExam = new string[3];
public byte[] rezultatExam = new byte[3];
}
Программа должна вводить исходные данные и определять сред¬
нюю оценку студента, фамилия которого определяется пользователем.
Поместим описание пользовательского класса в отдельный файл
Result.cs (рис. 2.13)и создадим форму (рис. 2.14).
Рисунок 2.13 - Описание пользовательского класса
90
Рисунок 2.14 - Вид формы в режиме конструктора
В данном примере, как и в нескольких следующих, используются
форма и элементы управления, полное описание которых приведено в
разделе 3.
Форма и программы процедур обработки событий обеспечивают
следующую логику работы. При загрузке формы меткам (label3,
label4, label5) присваиваются названия экзаменов и активизируется
командная кнопка «Ввод», командная кнопка «Вычисления» не ак¬
тивна. Последовательный пятикратный щелчок мышью по кнопке
«Ввод» после заполнения информацией текстовых окон, обеспечивает
получение необходимых входных данных. После этого командная
кнопка «Ввод» деактивируется, а командная кнопка «Вычисления»
активируется. После ввода в текстовое поле фамилии и щелчка мы¬
шью по кнопке «Вычисления» начинается вычисление средней оцен¬
ки студента и результат выводится в текстовое поле.
//Объявление массива типа пользовательского
//класса и счетчика по его элементам
Result[] session = new Result[5];
byte i=0;
private void Forml_Load(object sender,
EventArgs e)
{
//Настройка внешнего вида формы
label3.Text = "Физика";
91
label4.Text = "Математика";
label5.Text = "История";
button2.Enabled = false;
buttonl.Enabled = true;
}
private void buttonl_Click(object sender,
EventArgs e)
{
session[i] = new Result();
//Присваивание полю класса surname
значения,
//введенного в элемент textBoxl
session[i].surname = textBoxl.Text;
//Определение названий экзаменов как
//значений элементов класса
session[i].nameExam[0] = label3.Text;
session[i].nameExam[l] = label4.Text;
session[i].nameExam[2] = label5.Text;
//Ввод результатов экзаменов из текстовых
//элементов
session[i].rezultatExam[0] =
byte.Parse(textBox3.Text);
session[i].rezultatExam[l] =
byte.Parse(textBox4.Text);
session[i].rezultatExam[2] =
byte.Parse(textBox5.Text);
//Очистка текстовых элементов
textBoxl.Text =
textBox3.Text =
textBox4.Text =
textBox5.Text =
//Увеличение значения счетчика
+ + i;
if (i >= session.Length)
{
//В случае, если значение счетчика
92
//превышает длину массива (введены все
//его элементы) становится доступной
//кнопка «Вычисления»
buttonl.Enabled = false;
button2.Enabled = true;
}
}
private void button2_Click(object sender,
EventArgs e)
{
//Объявление переменных среднего балла и
//фамилии
float aver = 0;
//Запись введенной в элементе Text5 фамилии
//в переменную qwerySurname
string qwerySurname = textBox2.Text;
for (byte k=0; k< session.Length; k++)
{
//открытие цикла по введенным фамилиям
//Поиск соответствующего студента по
//фамилии
if (qwerySurname == session[k].surname)
{
aver = 0;
//открытие цикла по экзаменам для
//подсчета среднего балла
for (byte j =0; j <
session[k].rezultatExam.Length; j++)
{
aver +=
session[k].rezultatExam[j];
}
aver /=
session[k].rezultatExam.Length;
}
}
//Вывод среднего балла в элемент textBox6
textBox6.Text = aver.ToString();
}
93
2.9.2 Цикл с предусловием while
Цикл с предусловием реализует структурную схему, приведен¬
ную на рисунке 2.15, а.
Синтаксис оператора:
while (логическоеВыражение) оператор;
логическоеВыражение должно быть логического типа. Например,
это может быть операция отношения. Если результат вычисления вы¬
ражения равен true, выполняется простой или составной оператор.
Эти действия повторяются до того момента, пока результатом выра¬
жения не станет значение false. После окончания цикла управление
передается на следующий за ним оператор.
логическоеВыражение вычисляется перед каждой итерацией
цикла. Если при первой проверке выражение равно false, цикл не вы¬
полнится ни разу.
2.9.3 Цикл с постусловием do
Цикл с постусловием реализует структурную схему, приведен¬
ную нарисунке 2.15, б.
Рисунок 2.15 - Структурные схемы операторов цикла
94
Синтаксис оператора:
do оператор while (логическоеВыражение);
где
- do, while - ключевые слова;
- while - определяет выполнение операторов, входящих в цикл,
пока логическоеВыражение принимает значение true.
Сначала выполняется простой или составной оператор, образую¬
щий тело цикла, а затем вычисляется логическоеВыражение (оно
должно иметь тип bool). Если выражение истинно, тело цикла выпол¬
няется еще раз, и проверка повторяется. Цикл завершается, когда вы¬
ражение станет равным false или в теле цикла будет выполнен какой-
либо оператор передачи управления.
Этот вид цикла применяется в тех случаях, когда тело цикла
необходимо обязательно выполнить хотя бы один раз.
Пример 2.28. Организация циклов для считывания данных из
файла
do
{
s = f.ReadLine();
//Операторы обработки данных из файла
}
while (s != null)
while ((s = f.ReadLine()) != null)
{
//Операторы обработки данных из файла
}
В данном примере осуществляется последовательное чтение ин¬
формации из файла, с проверкой достижения конца файла. Анализ
наличия конца файла осуществляется с помощью проверки строки s,
считанной из файла f, на null.
Запись условия в конце цикла (вариант 1) означает, что цикл вы¬
полнится хотя бы один раз (при этом на первом проходе обычно фор¬
мируется условие, которое затем будет проверяться).
95
Пример 2.29. Вычисление ряда
Программа производит вычисления ряда с заданной точностью.
Элемент ряда N вычисляется по формуле: ((-1)AN)/(N!*(2*N+l)).
Программа реализуется в двух вариантах с использованием опе¬
раторов цикла с предусловием и постусловием. Каждый вариант рас¬
полагается в процедуре обработки события - щелчок мышью по соот¬
ветствующей командной кнопке (кнопки "Вариант1", "Вариант2") на
форме. Иллюстрации работы примера приведены на рисунке 2.16.
private void buttonl_Click(object sender,
EventArgs e)
{
//Объявление вспомогательных переменных и
//задание их первичных значений для
//проведения вычислений точности, суммы и
//значения факториала
double sum = 0, Nfactorial = 1;
int N = 1;
float eps = float.Parse(textBoxl.Text);
//Открытие цикла вычислений до достижения
//заданной точности
do
{
sum += Math.Pow(-l, N)/(Nfactorial * (2
* N + 1));
++N;
Nfactorial *= N;
}
while (Math.Abs(Math.Pow(-1, N) /
(Nfactorial * (2*N+1)))> eps);
//Вывод результатов вычислений
MessageBox.Show("CyMMa равняется " + sum +
", N равняется " + N);
}
96
Рисунок 2.16 - Общий вид формы примера
private void button2_Click(object sender,
EventArgs e)
{
//Объявление вспомогательных переменных и
//задание первичных значений для
//проведения вычислений точности, суммы и
//значения факториала
double sum = 0, Nfactorial = 1;
int N = 1;
float eps = float.Parse(textBoxl.Text);
//Открытие цикла вычислений до достижения
//заданной точности
while (Math.Abs(Math.Pow(-1, N) /
(Nfactorial * (2*N+1)))> eps)
{
sum += Math.Pow(-l, N)/(Nfactorial * (2
* N + 1));
N += 1;
Nfactorial *= N;
}
//Вывод результатов вычислений
MessageBox.Show("CyMMa равняется " + sum +
", N равняется " + N);
}
97
Пример 2.30. Использование различных вариантов операторов
цикла
int counter = 0,N = 100;
//Открытие цикла while по элементам массива В
do
{
//Присваивание элементам массива значений
//функции
massivB[counter] = Math.Sin(2.58 * counter);
++counter; //Увеличение значение счетчика
}
while (counter < N);
альтернативный код:
int counter =0, N= 100;
//Открытие цикла while по элементам массива В
while (counter < N)
{
//Присваивание элементам массива
//значений функции
massivB[counter] = Math.Sin(2.58 * counter);
++counter; //Увеличение значение счетчика
}
Эти два фрагмента программы эквивалентны следующему фраг¬
менту с использованием цикла for.
for (counter = 0; counter < N; counter++)
{
massivB[counter] = Math.Sin(2.58 * counter);
}
Одним из способов ввода нескольких значений элементов масси¬
ва может быть использование текстового окна и его свойств
SelLength, SelStart, SelText (раздел 3.5). В определенных пози¬
циях текстового окна можно задавать значения различных элемен¬
тов массива и с использованием указанных функций эти поля выде¬
лять.
98
Пример 2.31. Формирование списка с использованием циклов
Создадим форму и разместим на ней текстовое окно, определив
максимальное число символов 80 (свойство MaxLength = 80)
Каждый элемент массива занимает 4 позиции строки (количество
символов вводимого числа, включая десятичную точку, не превы¬
шает 4). Пробелы между числами отсутствуют.
Имя текстового окна inputTxt. Другие параметры определяются
по умолчанию. Определим процедуру обработки события: нажатие
клавиши KeyUp.
private void inputTxt_KeyUp(object sender,
KeyEventArgs e)
{
//Процедура обработки события отпускания
//клавиши клавиатуры в текстовом окне
//inputTxt
//Объявление массива
doublet] massivA = new double[5];
if (e.KeyCode == Keys.Enter)
{
//Если нажатая клавиша, соответствует
//клавише <Enter>
for (int i = 0; i< massivA.Length; i++)
{
//последовательно определяется
//начальная позиция вводимого
//числа
inputTxt.SelectionStart =i * 4;
inputTxt.SelectionLength = 4;
//выделяются необходимые символы и
//преобразуются в вещественные
//значения
massivA[i] =
double.Parse(inputTxt.SelectedText);
99
//отображение введенных значений
//как элементов списка
listBoxl.Items.Add(massivA[i]);
}
}
}
Процедура обеспечивает ввод значений пяти элементов массива
при нажатии клавиши <Enter>. На рисунке 2.17 показаны вводимые
символы и выделенные значения.
Рисунок 2.17 - Результат работы программы
2.9.4 Цикл перебора foreach
Оператор foreach применяется для перебора элементов в специ¬
альным образом организованной группе данных, например, массиве.
При применении foreach не требуется определять количество элемен¬
тов в группе и выполнять их перебор по индексу.
Синтаксис оператора:
foreach ( тип имя in выражение ) телоЦикла;
Имя задает локальную по отношению к циклу переменную, кото¬
рая будет по очереди принимать все значения из массива выражение
(в качестве выражения чаще всего применяется имя массива или дру¬
гой группы данных). В простом или составном операторе, представ¬
100
ляющем собой тело цикла, выполняются действия с переменной цик¬
ла. Тип переменной должен соответствовать типу элемента массива.
Пример 2.32. Использование оператора foreach
Пусть задан массив:
int[] а= {24, 50, 18, 3, 16, -7, 9, -1 };
Вывод элементов массива в текстовом поле с помощью оператора
foreach выглядит следующим образом:
foreach (int xina) { textBox2.Text +=
x.ToString() + "\r\n"; }
Этот оператор выполняется так: на каждом проходе цикла оче¬
редной элемент массива присваивается переменной х и с ней произ¬
водятся действия, записанные в теле цикла.
Ограничением оператора foreach является то, что с его помощью
можно только просматривать значения в группе данных, но не изме¬
нять их.
2.9.5 Совместное использование операторов цикла
и условного оператора
При одновременном использовании в коде программы операто¬
ров цикла и условных операторов должно выполняться так называе¬
мое правило вложенности.
Если среди операторов, которые выполняются в цикле (циклы
for, while, do и foreach), имеется условный оператор (if), то условный
оператор должен целиком размещаться внутри цикла (между фигур¬
ными скобочками в операторах for, while, do и foreach). Если в бло-
кеОператоров1 или блокеОператоров2 условного оператора if имеют¬
ся операторы, которые выполняются в цикле, (циклы for, while,
do и foreach), то эти циклы должны целиком содержаться в этих бло¬
ках.
На рисунке 2.18 приведены схемы, которые иллюстрируют
принцип корректного совместного использования циклов и условных
операторов.
101
—for (i = ...)
{
p if ( )
{
}
else
{ ••
L }
—}
-^f ( ) {
— for (i = ...) {
}
- }
— do
{.
if ( )
{
}
else
{
}
}
while ( )
if ( )
{
- do
{
}
— while ( )
}
Рисунок 2.18 - Схемы корректного совместного использования
операторов цикла и условных операторов
102
2.10 Контроль ошибок на этапе выполнения программы
Ошибки периода выполнения (runtime errors) могут возникать,
например, из-за нехватки памяти или дискового пространства, попыт¬
ки открыть открытый другим приложением файл, выхода индекса за
границы размерности массива и т, п. В этом случае IDE выводит диа¬
логовое окно с соответствующим сообщением и прекращает выпол¬
нение программы. Обработчик ошибок возвращает значение кода
ошибки, список которых находится в справочной системе (Help)
и документации к C#.
Ситуация (программный код), в процессе выполнения которой
возникла ошибка, называется исключительной. В языке C# есть опе¬
раторы, позволяющие обнаруживать и обрабатывать исключительные
ситуации, возникающие в процессе выполнения программы.
Исключения С# не поддерживают обработку асинхронных собы¬
тий, таких как ошибки оборудования или прерывания, например,
нажатие клавиш <Ctrl+C>.
Исключения позволяют логически разделить вычислительный
процесс на две части - обнаружение аварийной ситуации и ее обра¬
ботка. Это особенно актуально при использовании библиотечных
функций и программ, состоящих из многих модулей.
Исключения генерирует либо среда выполнения, либо разработ¬
чик с помощью оператора throw. В таблице 2.15 приведены наиболее
часто используемые стандартные исключения, генерируемые средой.
Они определены в пространстве имен System. Все они являются по¬
томками класса Exception, а точнее, потомками его потомка
SystemException.
Исключения обнаруживаются и обрабатываются в операторе try.
2.10.1 Оператор try
Оператор try содержит три части:
1) контролируемый блок - составной оператор, в начале которого
указывается ключевое слово try. В контролируемый блок включаются
потенциально опасные операторы программы. Все функции, прямо
или косвенно вызываемые из блока, также считаются ему принадле¬
жащими;
103
2) один или несколько обработчиков исключений - блоков catch,
в которых описывается, как обрабатываются ошибки различных ти¬
пов;
3) блок завершения finally выполняется независимо от того, воз¬
никла ошибка в контролируемом блоке или нет.
Стандартные исключения, которые наиболее часто используются
при написании приложений, приведены в таблице 2.16.
Синтаксис оператора try:
try блок [ блокиСаДсб. ] [ 6noKFinally ]
Отсутствовать могут либо блоки catch, либо блок finally, но не
оба одновременно.
Обобщенный алгоритм обработки исключительных ситуаций.
1. Обработка исключения начинается с появления ошибки. Функ¬
ция или операция, в которой возникла ошибка, генерирует исключение.
2. Выполнение текущего блока прекращается, происходит поиск
соответствующего обработчика исключения, которому передается
управление.
3. Выполняется блокFinaПy, если он присутствует.
4. Если обработчик не найден, вызывается стандартный обработ¬
чик исключения. Обычно он выводит на экран окно с информацией
об исключении и завершает текущий процесс.
Таблица 2.16 - Часто используемые стандартные исключения
Имя
Описание
DivideByZeroException
Попытка деления на ноль
FormatException
Попытка передать в метод аргумент неверного
формата
IndexOutOfRangeException
Индекс массива выходит за границы диапазона
InvalidCastException
Ошибка преобразования типа
OutOfMemoryException
Недостаточно памяти для создания нового объекта
OverflowException
Переполнение при выполнении арифметических
операций
StackOverflowException
Переполнение стека
Обработчики исключений должны располагаться непосредствен¬
но за блоком try. Они начинаются с ключевого слова catch, за кото¬
104
рым в скобках следует тип обрабатываемого исключения. Можно за¬
писать один или несколько обработчиков в соответствии с типами об¬
рабатываемых исключений. Блоки catch просматриваются в том по¬
рядке, в котором они записаны, пока не будет найден соответствую¬
щий типу выброшенного исключения.
Существуют три формы записи обработчиков:
1) применяется, когда имя параметра используется в теле обра¬
ботчика для выполнения каких-либо действий. Синтаксис:
catch( тип имя ) { ... /* тело обработчика */ }
2) не предполагает использования информации об исключении,
играет роль только его тип. Синтаксис:
catch( тип ) {.../* тело обработчика */ }
3) используется для перехвата всех исключений. Синтаксис:
catch { ... /* тело обработчика */ }
Так как обработчики просматриваются в том порядке, в котором
они записаны, обработчик третьего типа (он может быть только один)
помещают после всех остальных.
Пример 2.33. Использование оператора try
try {
... // Контролируемый блок
}
catch ( OverflowException е ) {
... // Обработка исключений класса
// OverflowException (переполнение)
}
catch ( DivideByZeroException ) {
... // Обработка исключений класса
// DivideByZeroException (деление на 0)
}
catch {
... // Обработка всех остальных исключений
}
105
Если исключение в контролируемом блоке не возникло, все об¬
работчики пропускаются.
Вне зависимости от того, произошло исключение или нет, управ¬
ление передается в блок завершения finally (если он существует), а
затем - первому оператору, находящемуся непосредственно за опера¬
тором try.
Операторы try могут многократно вкладываться друг в друга.
Исключение, которое возникло во внутреннем блоке try и не было
перехвачено соответствующим блоком catch, передается на верхний
уровень, где продолжается поиск подходящего обработчика.
2.10.2 Оператор throw
Для генерации исключения разработчиком используется опера¬
тор throw с параметром, определяющим вид исключения. Параметр
используется для передачи информации об исключении его обработ¬
чику и должен иметь тип System.Exception.
Синтаксис оператора throw:
throw [ выражение ];
Форма без параметра применяется только внутри блока catch для
повторной генерации исключения. Тип выражения, стоящего после
throw, определяет тип исключения, например,
throw new DivideByZeroException();
При генерации исключения выполнение текущего блока прекра¬
щается и происходит поиск соответствующего обработчика с переда¬
чей ему управления. Обработчик считается найденным, если тип объ¬
екта, указанного после throw, либо тот же, что задан в параметре
catch, либо является производным от него.
2.11 Файловый ввод-вывод
Архитектура современных компьютеров предусматривает нали¬
чие оперативной и внешней памяти. В оперативной памяти содержат¬
ся программы, которые выполняются в данный момент, и обрабаты¬
ваемые ими данные. После выполнения программы ее данные в опе¬
106
ративной памяти не сохраняются, так как используемые элементы
памяти выделяются для данных другой программы. Вследствие того,
что время доступа к данным на внешних носителях на один-два по¬
рядка ниже времени доступа к данным в оперативной памяти, хране¬
ние больших объемов информации на внешних носителях требует их
хорошо продуманной организации. А возможность альтернативного
хранения данных на различных внешних носителях требует использо¬
вания единых принципов организации данных.
Универсальным понятием для всех носителей данных является
файл (набор данных), который используется для работы с внешними
данными на любом носителе.
Файл - это совокупность данных, организованных в записи.
Запись состоит из логически связанных данных, передаваемых
между оперативной и внешней памятью за одну операцию ввода-
вывода (ввод - передача данных из внешней в оперативную память,
вывод - передача данных из оперативной во внешнюю память).
Запись характеризуется длиной. Записи бывают фиксированной
или переменной длины.
По способу доступа к записи файлы подразделяются на файлы
последовательного и прямого доступа. При последовательном досту¬
пе к любой записи файлов должны быть пройдены все предыдущие
записи, при прямом можно непосредственно перейти к нужной запи¬
си. Все внешние устройства позволяют использовать последователь¬
ный доступ к записям файла. Прямой доступ позволяют использовать
только устройства прямого доступа (например, магнитные и оптиче¬
ские диски).
В C# файлы подразделяются на:
- последовательные (sequential), записи которых могут быть
переменной длины;
- прямого доступа (random access), записи которых могут быть
только одинаковой длины;
- двоичные (binary) файлы с произвольной группировкой
байтов, что позволяет организовать гибкий доступ к данным.
Текстовые файлы C# позволяют выполнять только последова¬
тельный доступ, в двоичных и байтовых потоках можно использовать
оба метода.
107
Для работы с файлами независимо от языка программирования
обязательно нужно выполнить следующую последовательность дей¬
ствий:
1) описать переменную для доступа к файлу;
2) открыть доступ к файлу через описанную переменную;
3) выполнить действия с записями файла (читать записи из файла
или записывать в файл);
4) закрыть доступ к файлу.
В C# обмен данными реализуется с помощью потоков. Поток
(stream) - это абстрактное понятие, относящееся к любому переносу
данных от источника к приемнику. Потоки обеспечивают надежную
работу как со стандартными, так и с определенными пользователем
типами данных, а также единообразный и понятный синтаксис. Поток
определяется как последовательность байтов и не зависит от конкрет¬
ного устройства, с которым производится обмен (оперативная память,
файл на диске, клавиатура или принтер).
Обмен с потоком для повышения скорости передачи данных про¬
изводится, как правило, через специальную область оперативной па¬
мяти - буфер. Буфер выделяется для каждого открытого файла. При
записи в файл вся информация сначала направляется в буфер и там
накапливается до тех пор, пока весь буфер не заполнится. Только по¬
сле этого или после специальной команды сброса происходит переда¬
ча данных на внешнее устройство. При чтении из файла данные вна¬
чале считываются в буфер, причем не столько, сколько запрашивает¬
ся, а сколько помещается в буфер. Механизм буферизации позволяет
более быстро и эффективно обмениваться информацией с внешними
устройствами.
Для поддержки потоков библиотека .NET содержит иерархию
классов, основная часть которой представлена на рисунке 2.19. Эти
классы определены в пространстве имен System.I0. Помимо классов
там описано большое количество перечислений для задания различ¬
ных свойств и режимов.
Классы библиотеки позволяют работать в различных режимах с
файлами, каталогами и областями оперативной памяти. Краткое опи¬
сание классов приведено в таблице 2.17.
108
Рисунок 2.19 - Классы библиотеки .NET для работы с потоками
Таблица 2.17 - Основные классы пространства имен System.IO
Класс
Описание
BinaryReader,
BinaryWriter
Чтение и запись значений простых встроенных типов
(целочисленных, логических, строковых и т. п.)
во внутренней форме представления
BufferedStream
Временное хранение потока байтов (например,
для последующего переноса в постоянное хранилище)
Directory,
DirectoryInfo, File,
FileInfo
Работа с каталогами или физическими файлами: создание,
удаление, получение свойств. Возможности классов Fite
и Directory реализованы в основном в виде статических
методов. Аналогичные классы DirectoryInfo
и FileInfo используют обычные методы
FileStream
Произвольный (прямой) доступ к файлу,
представленному как поток байтов
MemoryStream
Произвольный доступ к потоку байтов
в оперативной памяти
StreamWriter,
StreamReader
Чтение из файла и запись в файл текстовой информации
(произвольный доступ не поддерживается)
StringWriter,
StringReader
Работа с текстовой информацией в оперативной памяти
109
Выполнять обмен с внешними устройствами можно на уровне:
- двоичного представления данных (BinaryReader,
BinaryWriter);
- байтов (FileStream);
- текста, то есть символов (StreamWriter, StreamReader).
В .NET используется кодировка Unicode (UTF-16), в которой
каждый символ кодируется двумя байтами. Классы, работающие с
текстом, являются оболочками классов, использующих байты, и ав¬
томатически выполняют перекодирование из байтов в символы и об¬
ратно.
Двоичные и байтовые потоки хранят данные в том же виде, в ко¬
тором они представлены в оперативной памяти, то есть при обмене с
файлом происходит побитовое копирование информации. Двоичные
файлы применяются не для просмотра их человеком, а для использо¬
вания в программах.
Каждый класс файловых потоков содержит несколько вариантов
конструкторов, с помощью которых можно создавать объекты этих
классов различными способами и в различных режимах.
Например, файлы можно открывать только для чтения, только
для записи или для чтения и записи. Эти режимы доступа к файлу со¬
держатся в перечислении FileAccess, определенном в пространстве
имен System.IO. Константы перечисления приведены в таблице 2.18.
Таблица 2.18 - Значения перечисления FileAccess
Значение
Описание
Read
Открыть файл только для чтения
ReadWrite
Открыть файл для чтения и записи
Write
Открыть файл только для записи
Возможные режимы открытия файла определены в перечислении
FileMode (табл. 2.19).
Режим FileMode.Append можно использовать только совместно с
доступом типа FileAccess.Write, то есть для файлов, открываемых для
записи.
Режимы совместного использования файла различными пользо¬
вателями определяет перечисление FileShare (табл. 2.20).
110
Таблица 2.19 - Значения перечисления FileMode
Значение
Описание
Append
Открыть файл, если он существует, и установить текущий
указатель в конец файла. Если файл не существует, создать
новый файл
Create
Создать новый файл. Если в каталоге уже существует файл
с таким же именем, он будет стерт
CreateNew
Создать новый файл. Если в каталоге уже существует файл
с таким же именем, возникает исключение IOException
Open
Открыть существующий файл
OpenOrCreate
Открыть файл, если он существует. Если нет, создать файл
с таким именем
Truncate
Открыть существующий файл. После открытия он должен
быть обрезан до нулевой длины
Таблица 2.20 - Значения перечисления FileShare
Значение
Описание
None
Совместное использование открытого файла запрещено.
Запрос на открытие данного файла завершается сообщением
об ошибке
Read
Позволяет открывать файл для чтения одновременно нескольким
пользователям. Если этот флаг не установлен, запросы
на открытие файла для чтения завершаются сообщением
об ошибке
ReadWrite
Позволяет открывать файл для чтения и записи одновременно
нескольким пользователям
Write
Позволяет открывать файл для записи одновременно нескольким
пользователям
2.11.1 Потоки байтов
Ввод-вывод в файл на уровне байтов выполняется с помощью
класса FileStream, который является наследником абстрактного клас¬
са Stream, определяющего набор стандартных операций с потоками.
Элементы класса Stream описаны в таблице 2.21.
Класс FileStream реализует эти элементы для работы с дисковы¬
ми файлами. Для определения режимов работы с файлом использу¬
ются стандартные перечисления FileMode, FileAccess и FileShare.
Значения этих перечислений приведены в таблицах 2.18- 2.20.
ill
Таблица 2.21 - Элементы класса Stream
Элемент
Описание
BeginRead,
BeginWrite
Начать асинхронный ввод или вывод
CanRead,
CanSeek,
CanWrite
Свойства, определяющие, какие операции поддерживает
поток: чтение, прямой доступ и/или запись
Oose
Закрыть текущий поток и освободить связанные
с ним ресурсы (сокеты, указатели на файлы ит.п.)
EndRead,
EndWrite
Ожидать завершения асинхронного ввода; закончить
асинхронный вывод
Flush
Записать данные из буфера в связанный с потоком
источник данных и очистить буфер. Если для данного
потока буфер не используется, то этот метод ничего
не делает
Length
Возвратить длину потока в байтах
Position
Возвратить текущую позицию в потоке
Read,
ReadByte
Считать последовательность байтов (или один байт)
из текущего потока и переместить указатель в потоке
на количество считанных байтов
Seek
Установить текущий указатель потока на заданную
позицию
SetLength
Установить длину текущего потока
Write,
WriteByte
Записать последовательность байтов (или один байт)
в текущий поток и переместить указатель в потоке
на количество записанных байтов
Пример 2.34. Использование потока байтов
Демонстрируются чтение и запись одного байта и массива бай¬
тов, а также позиционирование в потоке.
private void
noTOKMToolStripMenuIteml_Click(object sender,
EventArgs e)
{
FileStream f = new FileStreamCtest.txt",
FileMode.Create, FileAccess.ReadWrite);
f.WriteByte(lOO); //в начало файла
//записывается число 100
112
byte[] x = new byte[10];
byte i;
for (i = 0; i < 10; ++i)
{
x[i] = (byte)(10 - i);
f.WriteByte(i);
}
f.Write(x, 0, 5); // записывается 5
// элементов массива
byte[] у = new byte[20];
f.Seek(0, SeekOrigin.Begin); //текущий
//указатель - на
//начало
f.Read(y, 0, 20); //чтение из
//файла в массив
i = 0;
textBoxl.Visible = true;
foreach (byte elem in y)
{
textBoxl.Text += elem.ToString()+" ";
i++;
}
f.Seek(5, SeekOrigin.Begin); //текущий
//указатель - на
//5-й элемент
int а = f.ReadByte(); //чтение 5-го
элемента
textBoxl.Text +=
Environment.NewLine+a.ToStringO;
a=f.ReadByte();
//чтение 6-го
//элемента
textBoxl.Text
+=
Environment.NewLine
+
a.ToString();
textBoxl.Text
+=
Environment.NewLine
+
"Текущая позиция
в потоке "
+
f.Position.ToString();
f.Close();
}
113
Результат работы программы представлен на рисунке 2.20.
Рисунок 2.20 - Результат работы программы
Текущая позиция в потоке первоначально устанавливается на
начало файла (для любого режима открытия, кроме Append) и сдви¬
гается на одну позицию при записи каждого байта.
Для установки желаемой позиции чтения используется метод
Seek, имеющий два параметра: первый задает смещение в байтах от¬
носительно точки отсчета, задаваемой вторым. Точки отсчета задают¬
ся константами перечисления SeekOrigin: начало файла - Begin, те¬
кущая позиция - Current и конец файла - End.
В данном примере файл создавался в текущем каталоге. Можно
указать и полный путь к файлу, при этом удобнее использовать до¬
словные литералы.
FileStream f = new FileStream(
@"D:\CJ\test.txt", FileMode.Create,
FileAccess.ReadWrite);
В дословных литералах не требуется дублировать обратную ко¬
сую черту. Операции по открытию файлов могут завершиться не¬
удачно, например, при ошибке в имени существующего файла или
при отсутствии свободного места на диске, поэтому рекомендуется
всегда контролировать результаты этих операций. Обработку подоб¬
ных ситуаций следует предусмотреть в программе, например:
- FileNotFoundException, если файла с указанным именем в
указанном каталоге не существует;
114
- DirectoryNotFoundException, если не существует указанный
каталог;
- ArgumentException, если неверно задан режим открытия
файла;
- IOException, если файл не открывается из-за ошибок ввода-
вывода.
Возможны и другие исключительные ситуации.
Наиболее вероятные ошибки рекомендуется обрабатывать раз¬
дельно, чтобы предоставить пользователю программы в выводимом
сообщении наиболее точную информацию.
Пример 2.35. Обработка исключительных ситуаций при работе
с файлами
try
{
FileStream f = new FileStreamCtest.txt",
FileMode.Open, FileAccess.Read);
// действия с файлом
f.Close();
}
catch (FileNotFoundException err)
{
MessageBox.Show(err.Message+"\n Проверьте
правильность имени файла!");
return;
}
catch (Exception err)
{
MessageBox.Show("Error: " + err.Message);
return;
}
2.11.2 Потоки символов
Символьные потоки StreamWriter и StreamReader работают с
Unicode-символами, поэтому их чаще всего используют для работы с
файлами, предназначенными для восприятия человеком. Эти потоки
являются наследниками классов TextWriter и TextReader соответ¬
115
ственно, которые обеспечивают их большей частью функционально¬
сти. В таблицах 2.22 и 2.23 приведены наиболее важные элементы
этих классов. Следует отметить, что произвольный доступ для тек¬
стовых файлов не поддерживается.
Таблица 2.22 - Наиболее важные элементы базового класса
Text Writer
Элемент
Описание
Close
Закрыть файл и освободить связанные с ним ресурсы.
Если в процессе записи используется буфер, он будет
автоматически очищен
Flush
Очистить все буферы для текущего файла и записать накопленные
в них данные в место их постоянного хранения.
Сам файл при этом не закрывается
NewLine
Используется для задания последовательности символов,
означающих начало новой строки. По умолчанию используется
последовательность «возврат каретки» - «перевод строки»
Write
Записать фрагмент текста в поток
WriteLine
Записать строку в поток и перейти на другую строку
Таблица 2.23 - Наиболее важные элементы класса TextReader
Элемент
Описание
Peek
Возвратить следующий символ, не изменяя позицию указателя
в файле
Read
Считать данные из входного потока
ReadBlock
Считать из входного потока указанное пользователем количество
символов и записать их в буфер, начиная с заданной позиции
ReadLine
Считать строку из текущего потока и возвратить ее как значение
типа string. Пустая строка (null) означает конец файла (EOF)
ReadToEnd
Считать все символы до конца потока, начиная с текущей
позиции, и возвратить считанные данные как одну строку
типа string
Пример 2.36. Вывод в текстовый файл
using System.IO;
private void
BbiBOflB4>a^ToolStripMenuItem_Click(object sender,
EventArgs e)
{
try {
116
StreamWriter f = new
StreamWriterCtext.txt");
f.WriteLine("BbiBOfl в текстовый файл:"
);
double a = 12.234;
int b = 29;
string s = string.Format(" a = {0,6:C}
b= {1,2:X}", a, b);
f.WriteLine(s);
f.Close();
}
catch(Exception err) {
MessageBox.ShowC'OmxbKa: " + err.Message
);
return;
}
}
Пример 2.37. Чтение текстового файла
private void BBOflToolStripMenuItem_Click(object
sender, EventArgs e)
{
try
{
StreamReader f = new StreamReader
("text.txt");
string s = f.ReadToEnd();
textBoxl.Text = s;
f.Close();
}
catch (FileNotFoundException err)
{
MessageBox.Show("0mM6Ka: " + err.Message
+ "\n" + "Проверьте правильность имени
файла!");
return;
}
catch (Exception err)
{
117
MessageBox.Show("0mM6Ka: " +
err.Message);
return;
}
}
В примере 2.37 весь файл считывается целиком с помощью мето¬
да ReadToEnd и выводится в текстовое поле (рис. 2.21). Чаще возни¬
кает необходимость считывать файл построчно, такой пример приве¬
ден в примере 2.38. Каждая строка при выводе предваряется номером
(рис. 2.22).
Рисунок 2.21 - Результат работы примера чтения текстового файла
Пример 2.38. Построчное чтение текстового файла
private void
byLinesToolStripMenuItem_Click(object sender,
EventArgs e)
{
try
{
StreamReader f = new
StreamReader("text.txt");
string s;
long i=0;
textBoxl.Visible = true;
while ((s = f.ReadLine()) != null)
{
118
s = string.Format("{0} : {1}", ++i,
s);
textBoxl.Text += s +
Environment.NewLine;
};
f.Close();
}
catch (FileNotFoundException err)
{
MessageBox.Show("0mM6Ka: " + err.Message
+ "\n" + "Проверьте правильность имени
файла!");
return;
}
catch (Exception err)
{
MessageBox.Show("0mn6Ka: " +
err.Message);
return;
}
}
Рисунок 2.22 - Результат работы примера построчного чтения
текстового файла
Пример преобразования чисел, содержащихся в текстовом файле,
в их внутреннюю форму представления приведен в примере 2.39.
Пример 2.39. Преобразование строк в числа
В программе вычисляется сумма чисел в каждой строке. На со¬
держимое файла накладываются следующие ограничения: числа
119
должны быть разделены ровно одним пробелом, после последнего
числа в строке пробела быть не должно, файл не должен заканчивать¬
ся символом перевода строки. Методы разбиения строки и преобразо¬
вания в целочисленное представление рассматривались ранее. Резуль¬
тат вычисления по данным из файла представлен на рисунке 2.23.
try {
StreamReader f = new
StreamReaderCnumbers.txt") ;
string s;
const int n = 20;
int[] a = new int[n];
string[] buf;
int k = 0;
while ((s = f.ReadLine()) != null) {
buf = s.Split(' ') ;
long sum = 0;
for ( int i = 0; i < buf.Length; ++i )
{
a[i] = Convert.ToInt32(buf[i]);
sum += a[i];
}
s = string.Format("{0} сумма: {1}", s,
sum);
textBoxl.Text +=s +
Environment.NewLine;
}
f.Close();
}
catch ...
Рисунок 2.23 - Результат работы программы
120
2.11.3 Двоичные потоки
Двоичные файлы хранят данные в том же виде, в котором они
представлены в оперативной памяти, то есть во внутренней форме
представления. Двоичные файлы применяются не для просмотра их
человеком, а для использования в программах. Выходной поток
BinaryWriter поддерживает произвольный доступ, то есть имеется
возможность выполнять запись в произвольную позицию двоичного
файла. Двоичный файл открывается на основе базового потока, в ка¬
честве которого чаще всего используется поток FileStream. Входной
двоичный поток содержит перегруженные методы чтения для всех
простых встроенных типов данных. Основные методы двоичных по¬
токов приведены в таблице 2.24 и 2.25.
Таблица 2.24 - Наиболее важные элементы базового класса
BinaryWriter
Элемент
Описание
BaseStream
Базовый поток, с которым работает объект BinaryWriter
Close
Закрыть поток
Flush
Очистить буфер
Seek
Установить позицию в текущем потоке
Write
Записать значение в текущий поток
Таблица 2.25 - Наиболее важные элементы класса BinaryReader
Элемент
Описание
BaseStream
Базовый поток, с которым работает объект BinaryReader
Close
Закрыть поток
PeekChar
Возвратить следующий символ без перемещения внутреннего
указателя в потоке
Read
Считать поток байтов или символов и сохранить в массиве,
передаваемом как входной параметр
ReadXXXX
Считать из потока данные определенного типа (например,
ReadBoolean, ReadByte, ReadInt32 и т. д.)
Пример 2.40. Формирование двоичного файла
private void
binaryToolStripMenuItem_Click(object sender,
EventArgs e)
121
{
try {
BinaryWriter tout = new BinaryWrit-
er(new FileStream("binary", FileMode.
Create));
double d=0;
while (d<4) {
fout.Write(d);
d += 0.33;
};
fout.Seek(16,SeekOrigin.Begin);
// второй элемент
//файла
fout.Write( 8888d );
fout.Close();
}
catch ...
При создании двоичного потока в него передается объект базово¬
го потока. При установке указателя текущей позиции в файле учиты¬
вается длина каждого значения типа double - 8 байт. Попытка про¬
смотра сформированного программой файла в текстовом редакторе,
является неинформативной, поэтому в примере 2.41 приводится про¬
грамма, которая с помощью экземпляра BinaryReader считывает со¬
держимое файла в массив вещественных чисел, а затем выводит этот
массив в текстовое поле (рис. 2.3). При чтении принимается во вни¬
мание тот факт, что метод ReadDouble при обнаружении конца файла
генерирует исключение EndOfStreamException. Поскольку в данном
случае это не ошибка, тело обработчика исключений пустое.
Пример 2.41. Считывание двоичного файла
Результат считывания данных из двоичного файла "binary" вы¬
водится в элемент управления textBox1. Внешний вид формы пред¬
ставлен на рисунке 2.24.
private void
4TeHMeToolStripMenuItem_Click(object sender,
EventArgs e)
{
try
122
{
FileStream f = new FileStream("binary",
FileMode.Open);
BinaryReader fin = new BinaryReader(f);
textBoxl.Visible = true;
long n = f.Length / sizeof(double);
// количество чисел в файле
doublet] х = new double[n];
long i=0;
int k = 0;
try
{
// чтение
while (true)
x[i++] = fin.ReadDouble();
}
catch (EndOfStreamException err) { }
foreach (double d in x)
{
// вывод
textBoxl.Text += d.ToString() +
"\t";
}
fin.Close();
f.Close();
}
catch ...
Рисунок 2.24 - Результат работы программы
123
Пример 2.42. Обработка файла прямого доступа
Программа осуществляет преобразование текстового файла по¬
следовательного доступа таким образом, чтобы каждая цепочка сим¬
волов «*п», где n - однозначное целое число (количество пробелов),
заменялось определенным числом пробелов.
Ввод данных и управление работой программы осуществляется
с помощью формы (рис. 2.25).
Рисунок 2.25 - Результат работы примера
На форме располагаются элементы управления (использование
которых подробно рассматривается в разделе 3):
- командная кнопка "Ввод" (имя - buttonl), щелчок мышью по
которой активирует поле ввода (имя - textBoxl). Вводимая
информация записывается в файл последовательного досту¬
па;
- командная кнопка "Вывод1" (имя - button2), щелчок мышью
по которой обеспечивает отображение записей файла в мно¬
гострочном текстовом поле (имя - textBox2);
- командная кнопка "Преобразование" (имя - button3), щелчок
мышью по которой обеспечивает чтение записей из файла,
их преобразование в соответствии с заданием и сохранение
новых записей в другой файл;
- командная кнопка "Вывод2" (имя - button4), щелчок мышью
по которой обеспечивает отображение записей нового файла
в текстовом окне (имя - textBox3);
124
- щелчок мышью по кнопке "Конец" (имя - button5) прекра¬
щает выполнение программы.
public partial class Forml : Form
{
StreamReader file = null;
StreamWriter outFile = null;
const string inFileName = "Filel.txt";
const string outFileName = "File2.txt";
public Forml()
{
InitializeComponent();
}
private void buttonl_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчок
//мыши по кнопке "Ввод"
//Установка доступа текстового элемента
textBoxl.Enabled = true;
//Командная кнопка становится
//недоступной
buttonl.Enabled = false;
//открытие файла inFileName для чтения
file = new StreamReader(inFileName);
//Очистка элемента textBoxl
textBoxl.Text =
}
private void readFromFile(TextBox tb, string
fileName)
{
//Объявление строковой переменной
string fileData;
//Очистка элемента tb
tb.Text = "";
125
//Закрытие открытого файла
file.Close();
//открытие файла fileName для чтения
file = new StreamReader(fileName);
//открытие цикла, который будет
//выполняться пока не будет достигнут
//конец файла и чтение данных из файла
//в переменную fileData
while ((fileData = file.ReadLine()) !=
null)
{
//Вывод данных, которые были считаны
//из файла в элемент textBox2
tb.Text += fileData + "\r\n";
}
}
private void button2_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчок
//мыши по кнопке "Вывод1"
readFromFile(textBox2, inFileName);
}
private void button3_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчок
//мыши по кнопке "Преобразование"
//Объявление строковых переменных
string fileData, fileDatal =
//Объявление вспомогательных переменных
//для выполнения вычислений
byte nProbel;
//Закрытие открытого файла
file.Close();
126
//открытие файла inFileName для чтения
file = new StreamReader(inFileName);
//открытие файла outFileName для записи
outFile = new StreamWriter(outFileName);
//открытие цикла, который будет
//выполняться пока не будет достигнут
//конец файла outFileName и чтение
//данных из файла в переменную fileData
while ((fileData = file.ReadLine()) !=
null)
{
if (fileDatal != "")
{
//Очистка переменной fileDatal
fileDatal = "\r\n";
}
//Открытие цикла по подстрокам,
//каждая из которых начинается с
//символа "*"
foreach (string subData in
fileData.Split('*'))
{
//Копирование данных без
//символов "*п" из fileData в
//fileDatal
if (subData.Length > 0)
{
//Определение количества
//пробелов
nProbel = Con-
vert.ToByte(
subData.Substring(0, 1));
//Добавление необходимого
//количества пробелов
for (byte i = 0; i <
nProbel; i++)
fileDatal += "
fileDatal += sub-
Data.Substring(l);
}
}
127
//Вывод измененной строки в файл
outFile.Write(fileDatal);
}
//Закрытие открытых для чтения и записи
//файлов
file.Close();
outFile.Close();
button4.Enabled = true;
}
private void button4_Click(object sender,
EventArgs e)
{
readFromFile(textBox3, outFileName);
}
private void button5_Click(object sender,
EventArgs e)
{
this.Close();
}
private void textBoxl_KeyPress(object
sender, KeyPressEventArgs e)
{
//Процедура обработки события нажатия
//клавиши в элементе textBoxl
//Если нажата клавиша <Enter>
if (e.KeyChar == (char)Keys.Enter)
{
//то осуществляется вывод данных
//из элемента textBoxl
outFile.Write(textBoxl.Text);
//Очистка элемента textBoxl
textBoxl.Text =
outFile.CloseO;
}
}
}
128
Описание стандартных функций для обработки строк, которые
используются в примере, приведены в таблице 2.14.
2.11.4 Использование конструкции using
При работе с файлами для корректного закрытия потока можно
использовать конструкцию using, которая автоматически вызывает
метод Close(), когда объект потока выходит из области видимости.
Следующий код демонстрирует правильное применение ключевого
слова using в этом контексте:
FileStream fs = new FileStream(filePath,
FileMode.Append, FileAccess.Write);
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write("3anMCb...");
}
В соответствии с документацией, приведенный код полностью
эквивалентен следующему:
FileStream fs = new FileStream(filePath,
FileMode.Append, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
try
{
sw.Write("3anMCb...");
}
finally
{
if (sw != null)
sw.Close();
}
Пример 2.43. Работа с файлами для хранения информации о со¬
трудниках
Строки файла содержат информацию о сотрудниках подразделе¬
ния предприятия (структура записей файла: фамилия, имя, отчество,
пол, образование, год рождения, адрес, должность, подразделение, за¬
работная плата).
129
Программа обеспечивает ввод исходной информации в файл и
получения информации из запроса: средняя заработная плата для за¬
данных должности и подразделения.
Общий вид формы показан на рисунке 2.26.
Рисунок 2.26 - Общий вид формы с результатами выполнения
примера
Характеристики используемых элементов управления сведены в
таблицу 2.26, а их подробное описание приведено в разделе 3. Тек¬
стовые поля textBoxl - textBoxlO используются для ввода информа¬
ции и просмотра записей файла. Текстовые поля «Должность», «Под¬
разделение» (имена соответственно textBox9, textBoxlO) используют¬
ся для ввода параметров запроса. Текстовое поле «Результат» исполь¬
зуется для отображения результата и предупреждений о наличии не¬
заполненных текстовых полей. Командные кнопки «Начало/ввод»,
«Просмотр файла», «Ввод запроса», «Обработка запроса», «Конец»
(имена соответственно buttonl, button2, button3, button4, button5)
обеспечивают переход к функциональным алгоритмам. Пользова¬
тельский класс описан в отдельном файле Employee.cs.
130
Таблица 2.26 - Значение свойств элементов управления FormRecord
Элемент управления
Назначение
Имя
Тип
textBoxl
Фамилия
textBox2
Имя
textBox3
Отчество
textBox4
Год рождения
textBox5
Адрес
textBox6
Текстовое поле
Образование
textBox7
Должность
textBox8
Подразделение
textBox9
Заработная плата
textBoxlO
Запрашиваемая должность
textBoxll
Запрашиваемое подразделение
textBox12
Результат
comboBoxl
Выпадающий список
Образование
comboBox2
Пол
buttonl
Начало/ввод
button2
Просмотр файла
button3
Командная кнопка
Ввод запроса
button4
Обработка запроса
button5
Конец
public class Employee
{
public string surname;
public string name;
public string patronymic;
public int birthYear;
public string gender;
public string address;
public string education;
public string position;
public string subdivision;
public float salary;
public int workYear;
}
//Файл FormRecord.cs
131
//Объявление вспомогательных переменных
string filePath = "test.txt";
//Объявление переменной empl типа
//пользовательского класса
Employee empl;
private void FormRecord_Load(object sender,
EventArgs e)
{
//Процедура обработки события загрузки
//формы. Все элементы управления кроме
//buttonl устанавливаются недоступными
buttonl.Enabled = true;
button2.Enabled = false;
button3.Enabled = false;
button4.Enabled = false;
button5.Enabled = false;
textBoxl.Enabled = false;
textBox2.Enabled = false;
textBox3.Enabled = false;
textBox4.Enabled = false;
textBox5.Enabled = false;
textBox6.Enabled = false;
textBox7.Enabled = false;
textBox8.Enabled = false;
textBox9.Enabled = false;
textBoxlO.Enabled = false;
textBoxll.Enabled = false;
comboBoxl.Enabled = false;
comboBox2.Enabled = false;
}
private void addEmployee(Employee empl, string[]
arr)
{ //Процедура добавления атрибутов сотрудника
empl.surname = arr[0];
empl.name = arr[l];
empl.patronymic = arr[2];
empl.birthYear = Convert.ToInt32(arr[3]);
empl.address = arr[5];
132
empl.position = arr[6];
empl.subdivision = arr[7];
empl.education = arr[8];
empl.gender = arr[9];
empl.salary = Convert.ToSingle(arr[10]);
empl.workYear = Convert.ToInt32(arr[ll]);
}
private void buttonl_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчка мыши по
//кнопке «Начало/ввод»
string line;
string[] attrEmpl;
//открытие файла для чтения
using (StreamReader fs = new
StreamReader(filePath))
{
//открытие цикла, который выполняется
//пока не достигнут конец файла
while ((line = fs.ReadLineO) != null)
{
attrEmpl = line.Split(';');
addEmployee(empl, attrEmpl);
}
}
//Устанавливается доступность для ввода
//всех текстовых элементов формы
textBoxl.Enabled = true;
textBox2.Enabled = true;
textBox3.Enabled = true;
textBox4.Enabled = true;
textBox5.Enabled = true;
textBox6.Enabled = true;
textBox7.Enabled = true;
textBox8.Enabled = true;
textBox9.Enabled = true;
textBoxlO.Enabled = true;
133
textBoxll.Enabled = true;
comboBoxl.Enabled = true;
comboBox2.Enabled = true;
//Реализуется недоступность кнопки
//«Начало/ввод»
buttonl.Enabled = false;
}
private void clearTextBoxS()
{
//Очистка текстовых элементов
textBoxl.Text =
textBox2.Text =
textBox3.Text =
textBox4.Text =
textBox5.Text =
textBox6.Text =
textBox7.Text =
textBox8.Text =
textBox9.Text =
textBoxlO.Text = "";
textBoxll.Text =
}
private void button2_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчок мыши по
//кнопке «Просмотр файла»
//Считывание из файла строки с номером
//NRecordi
string tmpLine;
string[] arr;
clearTextBoxS();
tmpLine =
File.ReadLines(filePath).Skip(NRecordl).First();
arr = tmpLine.Split(';');
134
//Отображение значений записи в текстовых
//полях
textBoxl.Text = агг[0];
textBox2.Text = arr[l];
textBox3.Text = arr[2];
textBox4.Text = arr[3];
textBoxb.Text = arr[4];
textBox6.Text = arr[5];
textBox7.Text = arr[6];
comboBoxl.Text = arr[7];
comboBox2.Text = arr[8];
textBox8.Text = arr[9];
textBox9.Text = arr[10];
}
private void button3_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчка мыши по
//кнопке «Ввод запроса»
//Установка доступности полей для задания
//параметров запроса
textBox9.Enabled = true;
textBoxlO.Enabled = true;
//Очистка текстовых элементов
textBox9.Text = "";
textBoxlO.Text = "";
//Установка доступности кнопки «Обработка
//запроса»
button4.Enabled = true;
}
private void button4_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчка мыши по
//кнопке «Обработка запроса»
//Объявление строковых переменных
string requestl, request2, attrEmpl;
135
//Объявление переменной для вычисления суммы
float sum = 0;
//Объявление вспомогательных переменных и
//установка первоначальных значений
int num = 0;
bool prl = false, pr2 = false;
float rez;
//Получение параметров запроса
requestl = textBox9.Text;
request2 = textBoxlO.Text;
//открытие цикла
while ((line = fs.ReadLine()) != null)
{
attrEmpl = line.Split(';');
if (attrEmpl[6] == requestl)
{
//Если параметр с названием должности
//совпал, то вспомогательная
//переменная равняется true
prl = true;
}
if (attrEmpl[7] == request2)
{
//Если параметр с названием
//подразделения совпал, то
//вспомогательная переменная
//равняется true
pr2 = true;
}
if ((requestl == attrEmpl[6])&&(request2
== attrEmpl[7]))
{
//Если совпали и должность и
//подразделение, то увеличивается
//значение количества сотрудников и
136
//сумма их зарплаты
++num;
sum += Convert.ToSingle(arr[10]);
}
rez = sum/num;
//Определение средней зарплаты
if (!prl)
{
//Если вспомогательная переменная не
//установлена в true, то выводится
//сообщение, что подразделение не
//найдено
MessageBox.Show("TaKoe подразделение не
обнаружено!");
//Очистка текстового поля «Заработная
//плата»
textBox9.Text = "";
//переход на конец процедуры
break;
}
if (!pr2)
{
//Если вспомогательная переменная не
//установлена в true, то выводится
//сообщение, что должность не найдена
МеззадеВох.ЗЬои("Такой должности не
обнаружено!");
//Очистка текстового поля запрашиваемой
//должности
textBoxlO.Text = "";
//переход на конец процедуры
break;
}
//Вывод результата вычисления
textBoxll.Text = rez.ToString();
//Доступность кнопки «Выход»
137
button5.Enabled = true;
}
private void button5_Click(object sender,
EventArgs e)
{
//Процедура обработки события щелчок мыши
//по
//кнопке «Конец»
this.Close();
}
private bool checkText(char c, TextBox tb)
{
if (c == (char)Keys.Enter)
{
//Если нажата клавиша <Enter>
if (tb.Text == "")
{
//Если первое текстовое поле пустое,
//то в заголовке рамки выводится
//текст «Предупреждение»
groupBoxl.Text = "Предупреждение";
textBoxlO.Text = "Введите фамилию!";
}
return false;
}
else if (!(c >= 'A' && с <= 'Я') || (c >=
'а'&&с<='я') ||c=='-' ||c==' ' ||c==
(char)Keys.Back)
{
MessageBox.Show("B данное поле разрешен
ввод только кириллицы!");
return false;
}
return true;
}
private void textBoxl_KeyPress(object sender,
KeyPressEventArgs e)
{
//Процедура обработки события нажатия
138
//клавиши клавиатуры в текстовом поле
//ввода фамилии
checkText(e.KeyChar, textBoxl);
}
private string getSotrStr(Employee empl)
{
return empl.surname + + empl.name +
+ empl.patronymic + + empl.position + +
empl.education + + empl.gender + +
empl.address + "\r\n";
}
private void textBox9_KeyPress(object sender,
KeyPressEventArgs e)
{
//Процедура обработки события нажатия
//клавиши клавиатуры в текстовом поле
//ввода заработной платы
if (!checkText(e.KeyChar, textBox9))
{
//в случае, если проверки прошли
//успешно, осуществляется присваивание
//атрибутам пользовательского класса
//значений, введенных в текстовые
//поля
empl.surname = textBoxl.Text;
empl.name = textBox2.Text;
empl.patronymic = textBox3.Text;
empl.birthYear = textBox4.Text;
empl.address = textBox5.Text;
empl.position = textBox6.Text;
empl.subdivision = textBox7.Text;
empl.education = comboBoxl.Text;
empl.gender = comboBox2.Text;
empl.salary = textBox8.Text;
empl.workYear = textBox9.Text;
//открытие файла для записи
FileStream fs = new FileStream(filePath,
FileMode.Append, FileAccess.Write);
139
using (StreamWriter sw = new
StreamWriter(fs))
{
sw.Write(getSotrStr(empl));
}
//Установка доступности кнопкам
//«Просмотр файла» и «Ввод запроса»
button2.Enabled = true;
button3.Enabled = true;
clearTextBoxS();
}
}
Следует отметить, что процедуры textBoxKeyPress для ввода
данных аналогичны представленной процедуре textBoxlKeyPress за
исключением textBox9KeyPress в которой осуществляется запись
в текстовый файл.
Компьютер считывает информацию с диска секторами, даже если
размер записи меньше, то есть для каждой записи считывается хотя
бы один сектор и размещается в буфере памяти. Когда программа
считывает данные из дискового файла, она читает их из буфера. Когда
прочитывается весь буфер, компьютер читает в этот буфер следую¬
щие несколько секторов из файла. Аналогично данные записываются
в дисковый файл: сначала они записываются в буфер памяти, а когда
он заполняется, то записываются на диск.
Предположим, что размер дискового сектора 512 байтов, а длина
записи файла 260 байтов. При такой длине записи большинство запи¬
сей файла будут расположены в двух секторах (например, запись ис¬
пользует байты с 261 по 512 первого сектора и с 1 по 8 байт второго
сектора) и для чтения с диска такой записи будет нужно прочитать
два сектора. Использование вместо 260-байтных записей 256-байтных
обеспечивает упаковку в один дисковый сектор двух полных записей
и позволяет для ввода одной записи читать только один сектор.
Таким образом, выбор длины записи определяется типом и дли¬
ной переданных данных и размерами дисковых секторов. Реальная
длина переданных данных может быть меньше длины записи.
140
2.12 Выводы
Приведены сведения из основ семантики и синтаксиса языка C#,
к которым относятся: переменные, константы, операторы, масси¬
вы, циклы, файлы, пользовательские классы. После ознакомления
с материалами раздела, читатель может перейти к более сложным те¬
мам.
Перечень стандартных функций предоставлен в удобной таблич¬
ной форме. Раздел содержит примеры программ, которые предостав¬
ляют возможность читателю уяснить принципы использования ос¬
новных операторов языка, научиться структурировать программу.
Изучение материала дает возможность:
- ознакомиться с типами данных, которые доступны в C#, изу¬
чить области видимости переменных и время их существова¬
ния, научиться создавать и использовать переменные этих ти¬
пов;
- получить информацию о встроенных константах и константах
пользователя;
- изучить сложные типы данных на примере классов и струк¬
тур, научиться определять пользовательские типы данных
и использовать их;
- узнать о возможности использования одномерных, многомер¬
ных и ступенчатых массивов в C#, получить опыт использо¬
вания массивов при написании программ;
- изучить возможности использования арифметических и логи¬
ческих выражений, а также стандартных структур для обра¬
ботки текстовой информации, дат, значений времени и т. п.;
- ознакомиться с принципами использования оператора присва¬
ивания, условного оператора, оператора выбора, циклов;
научиться реализовывать сложные алгоритмы на языке C#;
- получить информацию о различных типах файлов, возможно¬
сти файлового ввода-вывода; приобрести опыт работы с фай¬
лами разных типов;
- научиться создавать собственные процедуры и функции и
применять их при написании программ.
141
2.13 Вопросы для повторения и контроля знаний
1. Типыпеременныхвязыке C#.
2. Определения области действия переменных.
3. Опишите пользовательский класс, который содержит инфор¬
мацию об автомобиле.
4. Какие операции можно выполнять с арифметическими, логи¬
ческими, символьными выражениями?
5. Как определить все включения фрагмента «информ» в строке
«Информационные системы управления позволяют получать инфор¬
мацию ...»?
6. Сформируйте дату из трех целых чисел.
7. Виды условных операторов.
8. Объясните использование оператора выбора.
9. Как определить константу?
10. Типы циклов. Замените цикл for циклом do.
11. Как описываются многомерные массивы? Как элементы мно¬
гомерного массива размещаются в памяти?
12. Как перехватить и обработать ошибку в процессе выполнения
программы?
13. Типы файлов. Принципы доступа к файлам.
14. Замените последовательный доступ к файлу прямым.
2.14 Задания для самостоятельного решения
1. Напишите процедуру или функцию, которая вычисляет пло¬
щадь прямоугольника. Аргументами могут быть или две стороны, или
величина диагонали и угол между ними, или длина одной стороны и
диагональ.
2. Напишите процедуру или функцию определения максималь¬
ного значения среди неопределенного количества значений.
3. Разработатьпроект,вкотором:
- вводится размер массива;
- формируется массив заданного размера и заполняется слу¬
чайными значениями;
- выполняется его обработка согласно заданию;
142
- выходные последовательности и результаты выводятся в
элементах ListBox.
4. Даны последовательности АиВ. Определить:
- сколько раз каждый из элементов Bi входит в последователь¬
ность A;
- количество элементов Bi, которые превосходят по значению
элементы Ai;
- есть ли в первой последовательности группа элементов, поря¬
док элементов которой совпадает с порядком во второй по¬
следовательности.
5. Задана последовательность X и числа у и z. Определить члены
последовательности, которые:
- большее иу,и z;
- меньше иу,и z;
- находятся между у и z.
6. Разработать проект, в котором:
- вводится размер массива;
- формируется массив заданного размера и заполняется случай¬
ными значениями;
- выполняется его обработка согласно заданию;
- результат выводится в элемент ListBox.
7. Задана последовательность чисел A. Считая пары значений
Ai, Ai+i координатами точки на плоскости, найти:
- количество треугольников, которые можно построить на вер¬
шинах с заданными координатами;
- количество отрезков с вершинами в заданных точках, лежа¬
щих полностью в первом квадранте;
- длину наибольшего отрезка, образованного заданными точками.
8. Разработать проект, в котором:
- вводится размер массива;
- формируется массив заданного размера и заполняется случай¬
ными значениями;
- выполняется его обработка согласно заданию;
- результат выводится в элементы TextBox.
9. Задана последовательность чисел А. Найти:
143
- среднегеометрическое, без учета максимального элемента;
- среднегеометрическое, без учета минимального элемента;
- среднегеометрическое, без учета минимального и максималь¬
ного элементов.
Определения минимального и максимального элементов, а также
вычисления геометрического среднего оформить в виде функций.
10. Задана последовательность чисел A. Найти:
- количество положительных элементов, окруженных слева
и справа по крайней мере одним отрицательным элементом;
- процент элементов, совпадающих по знаку со средним ариф¬
метическим;
- начало самой длинной последовательности из элементов од¬
ного знака.
Для формирования массива разработать метод-процедуру и ис¬
пользовать файлы прямого доступа.
11. Разработать проект, в котором необходимо:
- ввести размер матрицы;
- элементы матрицы вычисляются по формуле Aij = A/(B+i2)-
C*i*j. При этом коэффициенты определяются случайно. Диа¬
пазон формирования случайного числа вводится с помощью
элементов TextBox;
- вычисляется параметр Р, равный сумме положительных эле¬
ментов столбца, содержащего максимальный элемент матри¬
цы;
- если Р>15, то элементы столбцов матрицы, у которых среднее
арифметическое значение >0, упорядочить по возрастанию.
Все исходные значения и результаты обработки выводятся в
управляющих элементах или на форме по усмотрению разработчика.
144
3 ФОРМА И ЭЛЕМЕНТЫ УПРАВЛЕНИЯ
3.1 Выбор и использование элементов управления
Программные приложения строятся на основе форм, на формах
размещаются элементы управления. Это позволяет расширить функ¬
циональные возможности приложений и обеспечивает их всем необ¬
ходимым для взаимодействия с пользователем.
Элементы управления разделяются на визуальные и невизуаль¬
ные. Визуальные элементы управления являются элементами пользо¬
вательского интерфейса. Примеры элементов управления: кнопка
(Button), выпадающий список (ComboBox) или метка (Label). Неви¬
зуальные элементы управления не имеют пользовательского интер¬
фейса и не могут располагаться на форме. Visual Studio размещает их
внизу окна конструктора формы (рис. 3.1). Такими элементами
управления являются, например, Таймер (Timer) и всплывающая
подсказка (ToolTip).
Рисунок 3.1 - Визуальные и невизуальные элементы управления
145
Для размещения элемента на форме необходимо:
- первый способ - дважды щелкнуть на нужном значке на пане¬
ли элементов;
- второй способ - выбрать элемент на панели элементов щелч¬
ком мыши, а затем растянуть элемент в нужном месте формы.
После размещения элемента его имя появится в списке объектов
окна свойств.
3.2 Работа с формами
Формой называется главный элемент управления приложения, на
котором размещаются все другие элементы управления.
Для всех форм можно выделить следующие общие элементы:
1) граница придает форме необходимую степень гибкости. Она
может быть фиксированной, масштабируемой или отсутствовать. Тип
границы определяется свойством формы BorderStyle;
2) строка заголовка, на которой располагается специальный
текст. Двойной щелчок на заголовке меняет размеры формы (развер-
нуть/свернуть);
3) оконное меню содержит команды для восстановления, пере¬
мещения, изменения размеров, свертывания, развертывания и закры¬
тия формы (свойство ControlBox). Если значение этого свойство рав¬
няется true, то в строке заголовка появляются значок оконного меню
и кнопки. Если граница формы установлена как фиксированная, то
кнопки развертывания и свертывания формы отсутствуют. Наличие
этих кнопок, когда граница формы является масштабируемой (значе¬
ние Sizable), определяется свойствами MinimizeBox и MaximizeBox.
Основные свойства формы сведены в таблицу 3.1.
Список событий, связанных с формой, отображается в окне
свойств (рис. 1.11). Форма выбирается в верхнем выпадающем списке
и в режиме «События» можно посмотреть все события формы.
При работе с формой события происходят в следующем порядке:
- Load;
- Activated;
- FormClosing;
- FormClosed;
- Deactivate.
146
Таблица 3.1 - Основные свойства форм
Свойство
Описание
AcceptButton
Определяет кнопку по умолчанию (Default) для формы.
Данная кнопка реагирует на нажатие клавиши <Enter>.
На форме может быть только одна такая кнопка. В свойстве
выбирается одна из установленных на форме кнопок
AutoScroll
Получает или устанавливает значение, указывающее,
допускает ли форма автоматическую прокрутку
StartPosition
Положение формы в момент первого появления на экране.
Форма может находиться в центре экрана (CenterScreen),
в центре родительского окна (CenterParent). Если значение
свойства равно Manual, то положение формы определяется
значением свойства Location
FormBorderStyle
Тип формы (границы). Форма может представлять собой
обычное окно (Sizable), окно фиксированного размера
(FixedSingle, Fixed3D), диалог (FixedDialog) или окно без
кнопок Свернуть и Развернуть (SizableToolWindow,
FixedToolWindow). Если свойству присвоить значение
None, у окна не будет заголовка и границы
ControlBox
Управляет отображением оконного меню и кнопок
управления окном. Если значение свойства равно false,
то в заголовке окна кнопка системного меню, а также кнопки
Свернуть, Развернуть, Закрыть не отображаются
MaximizeBox
Кнопка Развернуть. Если значение свойства равно false, то
находящаяся в заголовке окна кнопка Развернуть недоступна
MinimizeBox
Кнопка Свернуть. Если значение свойства равно false,
то находящаяся в заголовке окна кнопка Свернуть
недоступна
Icon
Значок в заголовке окна
Opacity
Степень прозрачности формы. Форма может быть
непрозрачной (100 %) или прозрачной. Если значение
свойства меньше 100 %, то сквозь форму видна поверхность,
на которой она отображается
ShowIcon
Получает или устанавливает значение, указывающее,
отображается ли значок в полосе заголовка формы
ShowInTaskBar
Позволяет убрать форму с панели задач
WindowState
Определяет состояние формы при запуске приложения:
- Normal (в нормальном состоянии);
- Minimized (в свернутом состоянии);
- Maximized (разворачивается во весь экран)
147
Первые два события относятся к этапу инициализации формы.
Событие Load происходит после создания формы, но перед появле¬
нием ее на экране. Разница между событиями связана с существова¬
нием формы. Когда возникает событие Load, форма уже существует,
хотя пока еще и невидима.
Событие Activated происходит, когда форма становится видимой
и текущей.
Бывают ситуации, когда этот порядок может быть изменен. Если
во время конструирования свойство Visible установить в true или вы¬
звать метод Show (устанавливающий Visible в true), то событие Load
будет выполняться немедленно. Поскольку это также делает форму
видимой и текущей, также сразу выполняется событие Activated.
Событие FormClosing предоставляет возможность прервать про¬
цесс закрытия формы и позволяет установить значение параметра
CancelEventArgs. Этот аргумент имеет свойство Cancel, которое, бу¬
дучи установленным в true, прерывает событие и оставляет форму
открытой. Событие FormClosing происходит при попытке закрыть
форму, в то время как событие FormClosed - после ее закрытия. Оба
они дают возможность выполнить необходимую очистку. Отметим,
что событие Deactivate происходит уже после закрытия формы.
Чтобы пользователи могли взаимодействовать с приложением,
они должны видеть форму. Это обеспечивается методами Show и
ShowDialog. Метод Show просто делает форму видимой пользовате¬
лю. Когда вызывается метод Show, то код, следующий за этим вызо¬
вом, выполняется немедленно. Когда же вызывается ShowDialog, то
вызывающий код блокируется до тех пор, пока форма, чей метод
ShowDialog был вызван, не будет закрыта. При этом не только блоки¬
руется вызывающий код, но еще форма необязательно возвращает
значение DialogResult. Перечисление DialogResult представляет со¬
бой список идентификаторов, описывающих причину закрытия фор¬
мы. Они включают OK, Cancel, Yes, No и ряд других. Для того чтобы
форма возвратила DialogResult, должно быть установлено ее свой¬
ство DialogResult, либо же свойство DialogResult должно быть уста¬
новлено для одной из кнопок формы.
Событие Resize чаще всего используется для масштабирования
элементов управления или обновления выходных размеров формы.
148
При программном изменении значений свойств, для обращения
к свойствам и методам формы в пределах ее модуля используется
ключевое слово this.
Пример 3.1. Использование события Load для настройки внеш¬
него вида и поведения формы
private void Forml_Load(object sender, EventArgs
e)
{
this.Text = "Пример изменения внешнего вида
формы при ее загрузке";
//Установка красного цвета фона формы
this.BackColor = Color.Red;
}
Вид формы в режиме конструктора: цвет фона «серый» и текст
заголовка «Пока что ничего» определены в окне свойств. После за¬
пуска программы изменится текст заголовка формы и ее цвет станет
красным.
Пример 3.2. Изменение внешнего вида формы по выполнению
определенных событий
Внешний вид простейшего диалогового окна MessageBox, кото¬
рое появляется при закрытии формы, приведено нарисунке 3.2.
private void Forml_Click(object sender, EventArgs
e)
{
//Цвет фона формы изменяется на серый после
//щелчка мышью
this.BackColor = Color.Red;
}
private void Forml_DoubleClick(object sender,
EventArgs e)
{
//Цвет фона формы изменяется на желтый
//после двойного щелчка мышкой
149
this.BackColor = Color.Yellow;
}
private void Forml_KeyPress(object sender,
KeyPressEventArgs e)
{
int у = Screen.PrimaryScreen.Bounds.Height
/ 2;
if (e.KeyChar == (char)Keys.Return)
{
//Если нажата клавиша <Enter>,
//положение формы относительно
//границы экрана изменяется
this.Location =
Point(this.Location.X, у);
}
}
private void Forml_MouseDown(object sender,
MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
this.BackColor = Color.White;
//Нажатие правой кнопки мыши приведет
//к изменению цвета формы
//на белый
}
}
private void Forml_Resize(object sender,
EventArgs e)
{
//При попытке изменить размер формы, теку-
//щие
//значения ее высоты и ширины выводятся в
//заголовке формы
this.Text = "Изменение размеров формы.
Ширина: " + this.Width + ", высота: " +
this.Height;
}
то
верхней
new
150
private void Forml_FormClosing(object sender,
FormClosingEventArgs e)
{ //При попытке закрыть форму появляется
//диалоговое окно
if (MessageBox.Show("Bbi уверены, что хотите
выйти из программы?", "Внимание!",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{ //При нажатии кнопки «Да» закрытие
//приложения
Application.Exit();
}
else
{
//отменяет закрытие формы
e.Cancel = true;
}
}
Рисунок 3.2 - Диалоговое окно при закрытии формы
3.3 Элемент управления Label
(Метка или надпись)
Элемент управления Label (Метка) используется для вывода
символьной информации (заголовки других элементов, комментарии
или сопроводительная информация). Элемент управления Label
создается с помощью кнопки А и обладает основными свойствами,
которые сведены в таблицу 3.2.
Основные события элемента Label - это события Click и
DoubleClick, которым соответствуют процедуры обработки события
LabelClick или LabelDoubleClick. Также используются события
Mouse, но не используются события Key, потому что метка не может
получить фокус ввода.
151
Таблица 3.2 - Общие свойства элемента Label
Свойство
Описание
AutoSize
Признак автоматического изменения размера элемента
управления. Если значение свойства равно true, то при
изменении значения свойства Text (или Font) автоматически
изменяется размер элемента управления
MaximumSize
Если значение свойства AutoSize равно true, то задает
максимально допустимый (максимально возможный) размер
элемента управления (области отображения текста). Свойство
MaximumSize.Width задает максимально возможную ширину
области, свойство MaximumSize.Height - высоту
TextAlign
Способ выравнивания (расположения) текста в поле элемента
управления. Всего существует девять способов расположения
текста. На практике наиболее часто используют выравнивание
по левой верхней границе (TopLeft), посередине (ТорCenter)
и по центру (MiddleCenter)
BorderStyle
Вид рамки (границы) элемента управления. По умолчанию
граница вокруг поля Label отсутствует (значение свойства
равно None). Граница элемента управления может быть обычной
(Fixed3D) или тонкой (FixedSingle)
3.4 Элемент управления Button
(Кнопка или командная кнопка)
Элемент управления Button (Кнопка) - самый распространенный
элемент управления, который обычно активизирует какую-то опера¬
цию (вызывает выполнение команды). Данный элемент управления
создается кнопкой ® .
Специфические свойства элемента управления приведены
в таблице 3.3. Свойства размеров и расположения кнопки на форме,
а также цвет фона кнопки аналогичный таким же свойствам фор¬
мы.
152
Таблица 3.3 - Специфические свойства кнопки
Свойство
Описание
TextAlign
Положение текста на кнопке. Текст может располагаться в центре
кнопки (MiddleCenter), быть прижат к левой (MiddleLeft) или
правой (MiddleRight) границе. Можно задать и другие способы
размещения надписи (TopLeft, TopCenter, TopRight, BottomLeft,
BottomCenter, BottomRight)
FlatStyle
Стиль. Кнопка может быть стандартной (Standard), плоской (Flat)
или "всплывающей" (Popup)
Image
Картинка на поверхности кнопки. Рекомендуется использовать
png-файл, в котором определен прозрачный цвет
ImageAlign
Положение картинки на кнопке. Картинка может располагаться в
центре (MiddleCenter), быть прижата к левой (MiddieLeft) или
правой (MiddieRight) границе. Можно задать и другие способы
размещения картинки на кнопке (TopLeft, TopCenter, TopRight,
BottomLeft, BottomCenter, BottomRight)
ImageList
Набор изображений, из которых может быть выбрано то, которое
будет отображаться на поверхности кнопки. Представляет собой
объект типа ImageList. Чтобы задать значение свойства, в форму
приложения нужно добавить элемент управления ImageList
ImageIndex
Номер (индекс) изображения из набора ImageList, которое
отображается на кнопке
Чаще всего используются такие события командной кнопки:
Click, Enter, Leave, KeyDown, KeyPress, KeyUp, MouseDown,
MouseMove, MouseUp.
Пример 3.3. Использование командной кнопки
На форме установлены элементы управления метка (label1) и две
кнопки (button1, button2). Для формы в режиме конструктора уста¬
новлены кнопка по умолчанию (AcceptButton = button1) и кнопка
отмены (CancelButton = button2). Вид формы в режиме конструктора
приведен нарисунке 3.3.
private void button2_Click(object sender,
EventArgs e)
{
labell.Text = "Нажата кнопка 2";
}
153
sender,
private void buttonl_Click(object
EventArgs e)
{
labell.Text = "Нажата кнопка 1";
}
Рисунок 3.3 - Вид формы в режиме конструктора
3.5 Элемент управления TextBox
(Текстовое окно или текстовое поле)
Элемент управления TextBox (Текстовое поле) создается с помо¬
щью кнопки ® . Обычно текстовое поле определяет область экрана для
ввода или вывода информации пользователя и имеет уже рассмотрен¬
ные свойства: граница, доступность, шрифт, цвет фона, цвет текста,
имя, размеры и расположение, видимость, которые имеют то же назна¬
чение и значения параметров. Другие свойства приведены в таблице 3.4.
Наиболее часто используемые события: Click, Enter и Leave
(табл. 1.2). Событие TextChanged вызывается при изменении значе¬
ний свойств TextBox пользователем или программно. Набор каждого
нового символа генерирует данное событие и вызывает соответству¬
ющий обработчик.
Пример 3.4. Использование элемента управления TextBox
Разместим на форме элементы управления: два текстовых поля
(textBoxl и textBox2) и метку (labell) (рис. 3.4). Свойства элементов
управления заданы по умолчанию. Определим для первого текстового
окна (textBoxl) процедуры обработки событий Enter и Leave.
154
Таблица 3.4 -
Свойства элемента TextBox
Свойство
Описание
AcceptsTab
Определяет поведение клавиши <Tab> при многострочном
режиме элемента управления (Multiline = true). Если значение
свойства установлено в true, то при нажатии клавиши <Tab>
в окно элемента управления вставляется символ табуляции
(длинный пробел), в противном случае осуществляется переход
на следующий элемент управления
BorderStyle
Вид рамки (границы) элемента управления. Граница элемента
управления может быть обычной (Fixed3D), тонкой
(FixedSingle) или отсутствовать (None)
CharacterCasing
Определяет регистр набора текста в элементе управления:
- Normal (нормальный);
- Upper (все прописные);
- Lower (все строчные)
TextAlign
Способ выравнивания текста в поле элемента управления.
Текст в поле элемента управления может быть прижат к левой
границе элемента управления (Left), правой (Right) или
находиться по центру (Center)
MaxLength
Максимальное количество символов, которое можно ввести
в поле элемента управления
PasswordChar
Символ, который используется для отображения вводимых
пользователем символов (введенная пользователем строка
находится в свойстве Text)
Multiline
Разрешает (true) или запрещает (false) ввод нескольких строк текста
Readonly
Разрешает (true) или запрещает (false) редактирование
отображаемого текста
Dock
Способ привязки положения и размера элемента управления
к размеру формы. По умолчанию привязка отсутствует (None).
Если значение свойства равно Тор или Bottom, ширина
элемента управления устанавливается равной ширине формы
и элемент управления прижимается соответственно к верхней
или нижней границе формы. Если значение свойства Dock равно
Fill, а свойства Multiline - true, то размер элемента управления
устанавливается максимально возможным
HideSelection
Указывает, остается ли выделенным текст (значение false)
при потере фокуса элементом управления
Lines
Массив строк, элементы которого содержат текст, находящийся
в поле редактирования, если элемент управления находится
в режиме Multiline. Доступ к строке осуществляется по номеру.
Строки нумеруются с нуля
ScrollBars
Задает отображаемые полосы прокрутки:
Horizontal - горизонтальная; Vertical - вертикальная;
Both - горизонтальная и вертикальная; None - не отображать
WordWrap
Указывает, необходимо ли автоматически переносить по словам
текст при многострочном режиме элемента управления
155
Продолжение примера 3.4.
В первых двух процедурах первые два оператора изменяют раз¬
меры текстового окна. Третий оператор изменяет цвет фона окна.
Четвертый оператор определяет текст метки.
private void textBoxl_Enter(object sender,
EventArgs e)
{
//Процедура обработки события получения
//фокуса текстовым полем
textBoxl.Height = 100; //Установка высоты
textBoxl.Width = 150; //и ширины элемента
//Определение черного цвета фона
textBoxl.BackColor = Color.Black;
labell.Text = "Текстовое окно в фокусе";
}
private void textBoxl_Leave(object sender,
EventArgs e)
{
//Процедура обработки события потери фокуса
//текстовым полем
textBoxl.Height = 50; //Установка высоты
textBoxl.Width = 75; //и ширины элемента
//Определение серого цвета фона
textBoxl.BackColor = Color.Gray;
labell.Text = "Текстовое окно не в фокусе";
}
Щелкнув мышью по кнопке Пуск, запустим программу. Если
щелкнуть мышью по первому текстовому полю (активизировать дан¬
ный элемент управления), то первичная форма на рисунке 3.4, а при-
156
мет другой вид (рис. 3.4, б). Щелчок мышью по другому полю (первое
поле станет не активным) изменит вид формы (рис. 3.4, в).
а) этап
конструирования
б) результат
работы программы
в)активизация
текстового поля
Рисунок 3.4 - Пример использования элементов TextBox и Label
3.6 Элемент управления CheckBox (Флажок)
Элемент управления CheckBox (Флажок) может находиться в од¬
ном из двух состояний: если на квадратике флажка значок "X", то
флажок включен (активный), нет значка - флажок выключен. Щелчок
мышью по флажку устанавливает или выключает флажок. Любой
флажок функционально независим от других флажков и обычно ис¬
пользуется для установки или сброса параметров других элементов.
Флажок обладает уже рассмотренными свойствами: цвет фона,
заголовок, доступ, параметры шрифта, размеры и расположение, имя,
видимость, которые имеют то же назначение и значения параметров
(табл. 1.1). Элемент управления CheckBox создается кнопкой
Он может находиться в одном из двух состояний: выбранном или не¬
выбранном (часто вместо «выбранный» говорят «установленный»,
а вместо «невыбранный» - «сброшенный»). За состояние флажка от¬
вечает свойство Checked. Свойства элемента управления CheckBox
приведены в таблице 3.5.
157
Таблица 3.5 - Свойства элемента управления CheckBox
Свойство
Описание
Checked
Состояние флажка. Если флажок выбран (в поле элемента управления
отображается галочка), то значение свойства равно true.
Если переключатель сброшен (галочка не отображается),
о значение свойства равно false
TextAlign
Положение текста в поле отображения текста. Текст может располагаться
в центре поля (MiddleCenter), быть прижат к левой (MiddleLeft)
или правой (MiddleRight) границе. Можно задать и другие способы
размещения текста надписи (TopLeft, TopCenter, TopRight, BottomLeft,
BottomCenter, BottomRight)
CheckAlign
Положение флажка в поле элемента управления. Значок флажка
может быть прижат к левой верхней границе (TopLeft), прижат к левой
границе и находиться на равном расстоянии от верхней и нижней границ
поля элемента управления (MiddleLeft)
AutoCheck
Определяет, должно ли автоматически изменяться состояние флажка
в результате щелчка на его изображении. По умолчанию значение равно
true
FlatStyle
Стиль (вид) флажка. Флажок может быть обычным (Standard), плоским
(Flat) или "всплывающим" (Popup). Стиль определяет поведение
переключателя при позиционировании указателя мыши на его
изображении
Appearance
Определяет вид флажка. Флажок может выглядеть обычным образом
(Normal) или как кнопка (Button)
Image
Картинка, которая отображается в поле элемента управления
ImageAlign
Положение картинки в поле элемента управления. Картинка может
располагаться в центре (MiddleCenter), быть прижата к левой
(MiddleLeft) или правой (MiddleRight) границе. Можно задать
и другие способы размещения картинки на кнопке (TopLeft, TopCenter,
TopRight, BottomLeft, BottomCenter, BottomRight)
ImageList
Набор картинок, используемых для обозначения различных состояний
флажка. Представляет собой объект типа ImageList. Чтобы задать
значение свойства, в форму приложения следует добавить элемент
управления ImageList
ImageIndex
Номер (индекс) картинки из набора ImageList, которая отображается
в поле элемента управления
Если свойство ThreeState установлено в true, то свойство
CheckState элемента управления CheckBox может принимать одно из
следующих трех значений:
158
- Checked элемент CheckBox отмечен;
- Unchecked элемент CheckBox не отмечен;
- Indeterminate в этом состоянии значение элемента CheckBox
не определено.
События CheckedChanged и CheckStateChanged возникают, ко¬
гда изменяется свойство CheckState или Checked. Перехват этих со¬
бытий может пригодиться для установки других значений на основе
нового состояния CheckBox. Также флажок реагирует на события:
Click, Keypress, Enter и Leave, которые вызывают соответствующие
процедуры обработки этих событий.
3.7 Элемент управления RadioButton (Переключатель)
Элемент управления RadioButton (Переключатель) создается с
помощью кнопки ®. Он обычно задается в группе и позволяет вы¬
брать один вариант из нескольких возможных. Если один из пере¬
ключателей группы активен, другие отключены. Щелчок мышью на
одном из переключателей группы активизирует его и деактивизирует
другие переключатели группы.
Для группы флажков это правило не выполняется, все флажки
группы могут находится в активном или неактивном состоянии.
Свойство Checked (Состояние) может принимать значения:
true - переключатель активен, в центре круга жирная точка;
false - не активен. Свойства элемента управления приведены в табли¬
це 3.6.
Переключатель реагирует на уже рассмотренные события Click,
DoubleClick, Keypress, Enter и Leave, которые вызывают соответ¬
ствующие процедуры обработки этих событий.
Для корректного отслеживания изменения состояния переключа¬
теля используется событие CheckedChanged. Оно возникает всякий
раз, когда изменяется значение свойства Checked. Подобным образом
можно выполнить другие действия на основе нового значения эле¬
мента управления.
159
Таблица 3.6 - Свойства элемента управления RadioButton
Свойство
Описание
Checked
Состояние, внешний вид переключателя. Если переключатель
выбран, то значение свойства Checked равно true; если
переключатель не выбран, то значение свойства Checked равно false
TextAlign
Положение текста в поле отображения. Текст может располагаться
в центре поля (MiddleCenter), прижат к левой (MiddleLeft) или
правой (MiddleRight) границе. Можно задать и другие способы
размещения текста надписи (TopLeft, TopCenter, TopRight,
BottomLeft, BottomCenter, BottomRight)
CheckAlign
Положение кнопки в поле элемента управления. Переключатель
может быть прижат к левой верхней границе (TopLeft), прижат
к левой границе и находиться на равном расстоянии от верхней и
нижней границ поля элемента управления (MiddleLeft). Есть
и другие варианты размещения кнопки в поле элемента управления
AutoCheck
Свойство определяет, должно ли автоматически изменяться
состояние переключателя в результате щелчка на его изображении.
По умолчанию значение равно true
FlatStyle
Стиль переключателя. Переключатель может быть обычным
(Standard), плоским (Flat) или всплывающим (Popup).
Стиль переключателя определяет его поведение
при позиционировании указателя мыши на изображении
Appearance
Определяет вид переключателя. Переключатель может выглядеть
обычным образом (Normal) или как кнопка (Button)
Image
Картинка, которая отображается в поле элемента управления.
ImageAlign
Положение картинки в элементе управления. Картинка может
располагаться в центре (MiddleCenter), быть прижата к левой
(MiddleLeft) или правой (MiddleRight) границе. Можно задать
и другие способы размещения картинки на кнопке (TopLeft,
TopCenter, TopRight, BottomLeft, BottomCenter, BottomRight)
ImageList
Набор картинок, используемых для обозначения различных
состояний переключателя. Представляет собой объект типа
ImageList. Чтобы задать значение свойства, в форму приложения
нужно добавить элемент управления ImageList
ImageIndex
Номер (индекс) картинки из набора ImageList, которая
отображается в поле элемента управления
RightToLeft
Определяет месторасположение текста справа (no) или слева (yes)
от элемента управления
160
3.8 Контейнерные элементы управления Группа (GroupBox)
и Панель (Panel)
Следующие два элемента управления играют вспомогательную
роль и относятся к группе Контейнеры (Containers).
Элемент управления GroupBox создается с помощью кнопки
гХТп
ш и представляет собой контейнер для других элементов управления.
Обычно он используется для объединения в группы элементов управ¬
ления RadioButton по функциональному признаку. Элемент управле¬
ния GroupBox не обладает специфическими свойствами.
Элемент управления Panel представляет собой контейнер для
других элементов управления и позволяет легко управлять элемента¬
ми управления, которые находятся на панели. Например, для того,
чтобы сделать недоступными элементы управления, находящиеся на
панели, достаточно присвоить значение false свойству Enabled пане¬
ли. Свойства элемента управления Panel приведены в таблице 3.7.
Таблица 3.7 - Свойства элемента управления Panel
Свойство
Описание
AutoScroll
Предоставляет пользователю возможность прокручивания в случае,
если элементы управления размещаются за пределами видимых
границ панели
AutoSize
Определяет, подстраивается ли размер элемента управления, так
чтобы все содержащиеся в нем элементы управления были видны
(true)
Dock
Определяет границу формы, к которой привязана (прикреплена)
панель. Панель может быть прикреплена к левой (Left), правой
(Right), верхней (Тор) или нижней (Bottom) границе формы
BorderStyle
Вид границы панели; FixedSingle - рамка; Fixed3D - объемная
граница; None - граница не отображается
Пример 3.5. Программа с использованием элементов кнопка,
рамка, флажок и переключатель
Разработаем форму, которая предназначена для управления пла¬
тежами (оплата наличными или с использованием кредитных карто¬
чек, вид используемой карточки, оплата рублями). Она содержит ко¬
мандную кнопку для начала работы с формой, группу, объединяю¬
161
щую два переключателя для выбора наличной или безналичной опла¬
ты, группу, выделяющую флажок для определения оплаты рублями,
рамку, объединяющую два переключателя для выбора вида кредитной
карточки, и имеет вид, показанный на рисунке 3.5.
Рисунок 3.5 - Общий вид формы управления платежами
Подписи элементов управления (Начало, Метод платежа, Налич¬
ные, Кредитная карта, Рубли, Тип карты, Местный банк, VISA) зада¬
ны значением свойств Text перечисленных элементов формы.
При выводе формы на экран все элементы управления, кроме ко¬
мандной кнопки, должны быть неактивными (не реагировать на лю¬
бые события). Для этого свойству Enabled всех элементов управле¬
ния, кроме командной кнопки, в окне свойств присваивается значение
false.
Щелчок мышью по кнопке «Начало» активизирует группу выбо¬
ра метода платежа и переключателей, которые находятся в ней. Щел¬
чок мышью по переключателю «Наличные» активизирует соответ¬
ствующую группу и находящийся в ней флажок. Щелчок мышью на
переключателе «Кредитная карта» активизирует соответствующую
группу и находящийся в ней переключатель (переключатель «Налич¬
ные», при этом должен стать неактивным).
Такая логика работы диалоговой формы обеспечивается следую¬
щим программным кодом (использованы имена элементов управле¬
ния button1 - Командная кнопка, checkBox1 - Флажок, groupBox1,
groupBox2, groupBox3 - Рамки, radioButton!, radioButton2,
162
radioButton3, radioButton4 - переключатели устанавливаются по
умолчанию C#).
private void buttonl_Click(object sender,
EventArgs e)
{
//Процедура определения доступности
//элементов управления groupBoxl,
//radioButtonl, radioButton2 при
//щелчке мышью на кнопке «Начало»
groupBoxl.Enabled = true;
radioButtonl.Enabled = true;
radioButton2.Enabled = true;
}
private void radioButtonl_CheckedChanged(object
sender, EventArgs e)
{
//Процедура обработки события изменения
//значения переключателя «Наличные»
groupBox2.Enabled = true;
checkBoxl.Enabled = true;
groupBox3.Enabled = false;
radioButton3.Enabled = false;
radioButton4.Enabled = false;
}
private void radioButton2_CheckedChanged(object
sender, EventArgs e)
{
//Процедура обработки события изменения
//значения переключателя «Кредитная карта»
groupBox3.Enabled = true;
radioButton3.Enabled = true;
radioButton4.Enabled = true;
groupBox2.Enabled = false;
checkBoxl.Enabled = false;
}
163
Процедура button1_Click обработки события, связанного с
щелчком мыши по командной кнопке, обеспечивает активизацию
группы «Метод платежа» и расположенных в ней переключателей.
Процедура radioButtonlCheckedChanged обеспечивает активи¬
зацию группы «Наличные» и расположенного в ней флажка «Рубли».
Процедура radioButton2CheckedChanged обеспечивает активи¬
зацию группы «Кредитная карта» и расположенных в ней переключа¬
телей. Последние два оператора в каждой процедуре обеспечивают
деактивацию соответственно групп «Кредитная карта» и «Наличные»
и элементов в них, если они ранее были активны.
После запуска приложения увидим исходную форму (неактивные
элементы имеют бледную окраску) (рис. 3.6, а). Щелкнув мышью по
командной кнопке «Начало», увидим форму (рис. 3.6, б). Щелкнув
мышью по переключателю «Наличные», активизируем группу
«Наличные» и флажок «Рубли» (рис. 3.6, в). Щелчок мыши по пере¬
ключателю «Кредитная карта» активизирует соответствующую груп¬
пу и переключатели в ней, один из которых можно активизировать
(рис. 3.6, г).
а) исходный вид формы после
запуска
б) вид формы после нажатия
кнопки «Начало»
в) вид формы после выбора метода
платежа «Наличные»
г) вид формы после выбора
метода платежа
«Кредитная карта»
Рисунок 3.6 - Результат работы программы управления платежами
164
3.9 Элемент управления ListBox (Список)
Элемент управления ListBox (Список) позволяет вывести на
экран список вариантов (элементов списка - Items), которые могут
быть выбраны щелчком мыши (рис. 3.7). Минимальная высота списка
составляет три сроки. Длинный список, который не может быть выве¬
ден на экран целиком, обеспечивается полосой прокрутки (scroll bar).
Элемент управления ListBox создается с помощью кнопки .
Рисунок 3.7 - Элемент управления ListBox
Кроме рассмотренных уже свойств: BackColor, Enabled, Font,
ForeColor, Height, Width, Name и Visible, которые имеют такие же
назначения и значения параметров, которые приведены в таблице 1.1,
элемент ListBox имеет специфические свойства (табл. 3.8).
Список реагирует на уже рассмотренные события: Click,
DoubleClick, KeyPress, Enter, Leave, которые вызывают соответ¬
ствующие процедуры обработки этих событий (табл. 1.2).
Наиболее часто используемые методы списка Items элемента
управления ListBox, сведены в таблицу 3.9.
3.10 Элемент управления ComboBox
(Комбинированный список)
Элемент управления ComboBox (Комбинированный список) со¬
четает текстовое окно (поле ввода) с обычным списком в один эле¬
мент управления (рис. 3.8). Для создания элемента ComboBox приме¬
няется кнопка ^ панели элементов. Комбинированный список не
позволяет размещать элементы в несколько колонок.
165
Таблица 3.8 - Свойства элемента управления ListBox
Свойство
Описание
ColumnWidth
Задает ширину столбцов в многоколонном элементе
управления
HorizontalScrollbar
Задает значение, указывающее, отображается ли полоса
горизонтальной прокрутки в элементе управления
Items
Элементы списка - коллекция строк
Items.Count
Количество элементов списка
ScrollAlwaysVisible
Задает значение, указывающее, всегда ли показывается
вертикальная полоса прокрутки
SelectedIndex
Номер элемента, выбранного в списке. Если ни один из
элементов списка не выбран, то значение свойства равно - 1
Sorted
Признак необходимости автоматической сортировки (true)
списка после добавления очередного элемента
SelectionMode
Определяет режим выбора элементов списка: One - только
один элемент; MultiSimple - можно выбрать несколько
элементов, сделав щелчок на нужных элементах списка;
MultiExtended - можно выбрать несколько элементов,
сделав щелчок на нужных элементах списка при нажатой
клавише <Ctrl>, или выделить диапазон, щелкнув при
нажатой клавише <Shift> на первом и последнем элементе
диапазона
MultiColumn
Признак необходимости отображать список в несколько
колонок. Число отображаемых колонок зависит от
количества элементов и размера области отображения
списка
Таблица 3.9 - Основные методы списка Items элемента
управления ListBox
Метод
Описание
Add
Включает элемент (строку текста) в список.
Синтаксис:
имяСписка.1Детз.АДД(строка)
Если значение свойства Sorted равняется true, то элемент
размещается в соответствии с алфавитным порядком, иначе элемент
автоматически располагается в конце списка.
Clear
Удаляет из списка все элементы.
Синтаксис:
имяСписка.1Детз.С1еаг()
RemoveAt
Убирает из списка элемент с заданным индексом.
Синтаксис:
HMflCnncKa.Items.RemoveAt(nHfleKc)
166
Рисунок 3.8 - Элемент управления ComboBox
Комбинированный список имеет уже рассмотренные свойства:
BackColor, Enabled, Font, ForeColor, Height, Width, Name и Visible
(табл. 1.1). Специфические свойства элемента управления ComboBox
приведены в таблице 3.10.
Комбинированный список реагирует на уже рассмотренные со¬
бытия Click, DoubleClick, Keypress, Enter, Leave (табл. 1.2), которые
вызывают соответствующие процедуры обработки этих событий.
Основные методы элемента управления ComboBox аналогичны
методам элемента ListBox (табл. 3.8).
Таблица 3.10 - Свойства элемента управления ComboBox
Свойство
Описание
DropDownStyle
Вид элемента управления: DropDown - поле ввода
и раскрывающийся список; Simple - поле ввода со
списком; DropDownList - раскрывающийся список
MaxDropDownItems
Количество отображаемых элементов в раскрытом списке.
Если количество элементов списка больше, чем
MaxDropDownItems, то появляется вертикальная полоса
прокрутки
Size
Размер элемента управления без (для элементов
управления типа DropDown и DropDownList) или
с учетом (для элемента управления типа Simple) размера
области списка или области ввода
DropDownWidth
Ширина области списка
167
Пример 3.6. Использование элементов управления Список и
Комбинированный список
Создадим новый проект и разместим на форме следующие управ¬
ляющие элементы: два списка в верхней части формы и три комбиниро¬
ванных списка - в нижней, снабдив их заголовками (метки).
Имена элементов задаются по умолчанию (последовательно слева
направо списки: listBoxl и listBox2, комбинированные списки:
comboBoxl, comboBox2, comboBox3).
Значения свойства DropDownStyle: для комбинированного спис¬
ка comboBoxl зададим Simple, для comboBox2 - DropDown, для
comboBox3 - DropDownList. Размер окна для комбинированного
списка comboBox1 нужно определить при размещении элемента на
форме. Форма имеет вид, приведенный на рисунке 3.9.
Рисунок 3.9 - Вид формы с элементами ListBox и ComboBox
в режиме конструктора
Определим следующие процедуры обработки событий: Form1Load,
listBox1DoubleClick, listBox2DoubleClick, comboBox1KeyPress и
comboBox2_KeyPress.
168
private void Forml_Load(object sender, EventArgs
e)
{
//Определение содержимого элементов
//управления listBoxl, comboBoxl, comboBox2
//и сотЬоВохЗ
//Добавление текста в список элемента
//listBoxl
//Заполнение списка студентов
listBoxl.Items.Add("HBaHOB И.И.");
HstBoxl.Items.Add("neTpoB П.П.");
listBoxl.Items.Add("CnflopoB С.С.");
//Добавление текста в список элемента
//сотЬоВохЗ
//Заполнение списка оценок
comboBox3.Items.Add("HeyflOBn.");
comboBox3.Items.Add("yflOBneTB.");
comboBox3.Items.Add("Xopomo");
comboBox3.Items.Add("0Tnn4Ho");
//Добавление текста в список элемента
//comboBox2
//Заполнение списка студентов, сдавших
//экзамен
сотЬоВох2.1бетз.Абб("Михайлов М.М.");
comboBox2.Items.Add("HHKonaeB Н.Н.");
//Добавление текста в список элемента
//comboBoxl
//Заполнение списка дисциплин
comboBoxl.Items.Add("3M3HKa");
comboBoxl.Items.Add("MaTeMaTHKa");
comboBoxl.Items.Add("McTopnH");
}
private void comboBoxl_KeyPress(object sender,
KeyPressEventArgs e)
{
//Процедура обработки события нажатия
169
//клавиши клавиатуры в элементе comboBoxl
if (e.KeyChar == (char)Keys.Enter)
{ //Если нажата клавиша <Enter>, то
//уточняем у пользователя необходимость
//добавления
if (MessageBox.Show("flo6aBHTb?",
"Внимание!",
MessageBoxButtons.YesNo) ==
DialogResult.Yes)
{ //Если пользователь в диалоговом
//окне нажал на кнопку «Да»,
//добавляем набранный в
//элементе текст в список
comboBoxl.Items.Add(comboBoxl.Text);
}
}
}
private void comboBox2_KeyPress(object sender,
KeyPressEventArgs e)
{
//Процедура обработки события нажатия
//клавиши клавиатуры в элементе comboBox2
if (e.KeyChar == (char)Keys.Enter)
{ //Если нажата клавиша <Enter>, то
//уточняем у пользователя необходимость
//добавления
if (MessageBox.Show("Добавить?",
"Внимание!", MessageBoxButtons.YesNo) ==
DialogResult.Yes)
{ //Если пользователь в диалоговом
//окне нажал на кнопку «Да»,
//добавляем набранный в
//элементе текст в список
comboBox2.Items.Add(comboBox2.Text);
}
}
}
170
private void listBoxl_DoubleClick(object sender,
EventArgs e)
{
//Процедура обработки события двойного
//щелчка мышью на элементе listBoxl.
//Перенесение студента из общего списка в
//список студентов, которые сдали экзамен
//Добавление в список элементов listBox
//текста, который выделен в элемент listBoxl
listBox2.Items.Add(listBoxl.Text);
//Удаление текущего элемента списка
listBoxl.Items.Remove(listBoxl.Selectedltem)
}
private void listBox2_DoubleClick(object sender,
EventArgs e)
{
//Процедура обработки события двойного
//щелчка мышью на элементе listBox2.
//Перенесение студента из списка
//сдавших экзамен, в общий список
//Добавление в список элементов listBoxl
//текста, который выделен в элементе
//listBox2
listBoxl.Items.Add(listBox2.Text);
//Удаление текущего элемента списка
listBox2.Items.Remove(listBox2.Selectedltem)
}
Процедура Form_Load обеспечивает формирование информа¬
ции, отображаемой в списках. Процедуры listBox1_DoubleClick и
listBox2_DoubleClick обеспечивают при двойном щелчке мышью по
одному из элементов списка перемещение этого элемента в другой
список. Процедуры comboBox1_KeyPress и comboBox2_KeyPress
обеспечивают введение набранного текста в строке ввода и помеще¬
ние в соответствующий список при нажатии клавиши <Enter>. После
171
запуска программы выводится форма (рис. 3.10). Двойной щелчок
мышью по одному из элементов верхних списков переносит этот эле¬
мент в другой список.
Элементы левого комбинированного списка постоянно отобра¬
жаются в окне. Элементы центрального комбинированного списка
отображаются в раскрывающемся окне после щелчка мышью по
стрелке. Элементы правого комбинированного списка появляются в
раскрывающемся окне после щелчка мышью по стрелке. Для первых
двух элементов ComboBox существует возможность выбора варианта
из списка или ввода нового значения в список, при введении его в
строке ввода. Для третьего элемента существует возможность только
выбора значения из фиксированного списка.
Рисунок 3.10 - Результат работы программы
172
3.11 Элемент управления ToolTip
Элемент управления ToolTip - вспомогательный, он использует¬
ся другими элементами управления формы для вывода подсказок при
позиционировании указателя мыши (рис. 3.11). Этот элемент управ¬
ления на форме создается с помощью кнопки ^ . Свойства элемента
управления приведены в таблице 3.11.
Рисунок 3.11 - Элемент управления ToolTip
Таблица 3.11 - Свойства элемента управления ToolTip
Свойство
Описание
Active
Разрешает (true) или запрещает (false) отображение подсказок
AutoPopDelay
Время отображения подсказки
InitialDelay
Время, в течение которого указатель мыши должен быть
неподвижным, чтобы появилась подсказка
ReshowDelay
Время задержки отображения подсказки после перемещения
указателя мыши с одного элемента управления на другой
3.12 Элемент управления PictureBox (Графическое поле)
Элемент управления PictureBox (Графическое поле) часто ис¬
пользуется для отображения графических файлов. Изображение
может быть в формате BMP, JPEG, GIF, PNG, метафайла или
пиктограммы. Этот элемент управления на форме создается с помо¬
щью кнопки ^ . Специфические свойства элемента управления
PictureBox сведены в таблицу 3.12.
При создании PictureBox сначала создается объект, базирую¬
щийся на Image.
173
Пример 3.7. Загрузка JPEG файлав PictureBox
Bitmap myjpeg = new BitmapCmypic.jpg");
pictureBoxl.Image = (Image)myJpeg;
/^Поскольку свойство Image элемента управления
PictureBox имеет тип Image, то возникает
необходимость приведения к данному типу.*/
Таблица 3.12 - Свойства элемента PictureBox
Свойство
Описание
BorderStyle
Вид границы элемента управления: None - граница
не отображается; FixedSingle - тонкая; Fixed3D -
объемная
ClientSize
Размер отображения элемента
Image
Иллюстрация, которая отображается в поле
компонента
Image.PhysicalDimension
Свойство содержит информацию об истинном
размере картинки (иллюстрации), загруженной
в поле компонента
SizeMode
Метод отображения (масштабирования) иллюстрации,
если ее размер не соответствует размеру элемента
управления:
Normal - масштабирование не выполняется (если раз¬
мер элемента управления меньше размера иллюстра¬
ции, то отображается только часть иллюстрации);
StretchImage - выполняется масштабирование иллю¬
страции так, чтобы она занимала всю область элемента
управления (если размер элемента управления
не пропорционален размеру иллюстрации,
иллюстрация искажается);
AutoSize - размер элемента управления автоматически
изменяется в соответствии с размером иллюстрации;
CenterImage - центрирование иллюстрации в поле
элемента управления, если размер иллюстрации
меньше размера элемента управления;
Zoom - изменение размера иллюстрации таким о
бразом, чтобы она занимала максимально возможную
область элемента управления и при этом отображалась
без искажения (с соблюдением пропорций)
Initiallmage
Некоторое начальное изображение, которое будет
отображаться во время загрузки главного изображения,
которое хранится в свойстве Image
Errorlmage
Изображение, которое отображается, если основное
изображение не удалось загрузить в PictureBox
174
3.13 Элемент управления ImageList
Элемент управления ImageList (список графических изображе¬
ний) создается с помощью кнопки ® и предназначен для размещения
изображений на кнопках панели инструментов, узлов дерева, в таб¬
личном списке, комбинированном поле с изображениями и т. п.
Обычно этот элемент управления применяется для хранения коллек¬
ции изображений, используемых в качестве пиктограмм в панели ин¬
струментов или пиктограмм в других элементах управления. Элемент
ImageList не является визуальным.
Ключевым свойством ImageList является свойство Images, кото¬
рое задает коллекцию изображений. При выборе данного свойства от¬
крывается окно редактора коллекции изображений (рис. 3.12), в кото¬
ром можно добавить новое изображение или удалить имеющееся.
Рисунок 3.12 - Окно редактора коллекции изображений
Свойство Images элемента ImageList возвращает ImageCoUection.
Два наиболее часто используемых свойства - это ImageSize и
ColorDepth.
175
ImageSize получает в качестве значения структуру Size. По
умолчанию выбран размер 16x16, но допускается любое значение от 1
до 256.
ColorDepth использует значения перечисления ColorDepth. Глу¬
бина цвета может быть в пределах от 4 до 32 бит.
Изображения добавляются в элемент управления ImageList с по¬
мощью метода Add свойства ImageList.Images.
imageListl.Images.Add(Image.FromFile(@"C:\Users
\Eugene\Pictures\uruguay.png"));
// удаляем первое изображение
imageListl.Images.RemoveAt(O);
Большинство элементов управления включают в себя свойство
ImageList. Свойство ImageList обычно идет в комплекте с
ImageIndex. Свойству ImageList присваивается элемент управления
ImageList, а свойству ImageIndex - индекс в ImageList, представля¬
ющий изображение, которое подлежит отображению в элементе
управления.
Пример 3.8. Использование ImageList
private void listBoxl_Click(object sender,
EventArgs e)
{
pictureBoxl.Image =
imageListl.Images[listBoxl.SelectedIndex];
}
3.14 Элемент управления Timer (Таймер)
Таймер принадлежит к элементам, которые никогда не отобра¬
жаются в момент выполнения программы, поэтому для них не выде¬
ляется место на форме. Элемент Таймер создается с помощью кнопки
и выполняет только одну функцию - проверяет показания систем¬
ных часов и действует соответственно полученному результату.
Таймер имеет очень мало свойств: кроме Name, Enabled следует
обратить внимание на свойство Interval (задается в миллисекундах) -
176
после окончания заданного интервала времени генерируется событие
Tick. Чтобы событие Tick не происходило после окончания заданного
периода, можно установить значение свойства Enabled в false.
3.15 Элементы управления HScrollBar и VScrollBar
(Полосы прокрутки)
ScrollBar (Полоса прокрутки) - это элемент управления, содер¬
жащий в себе Thumb (бегунок), с помощью которого пользователь
может выбирать значение. Полоса прокрутки может использоваться,
например, если документ не помещается на экране. Некоторые более
сложные элементы управления содержат полосы прокрутки, чтобы
можно было просматривать не умещающееся в них содержимое.
Элемент управления «Полоса прокрутки» создается кнопками
IQ
“ и VScrollBar 3 . Они применяются для установки
числового значения из заданного диапазона и позволяют узнавать
значение этой величины по позиции бегунка на полосе прокрутки, ко¬
торое может быть только целым.
Свойства полосы прокрутки, которые чаще всего используются,
приведены в таблице 3.13.
Таблица 3.13 - Свойства элементов HScrollBar и VScrollBar
Свойство
Значение
Value
Возвращает или задает значение, соответствующее текущему
положению бегунка элемента управления из диапазона
Maximum
Возвращает или задает максимальное возможное значение Value
Minimum
Возвращает или задает минимальное значение Value
LargeChange
Возвращает или устанавливает шаг изменения значения при
щелчке между бегунком и одной из стрелок полосы прокрутки
SmallChange
Возвращает или устанавливает шаг изменения значения
при щелчке по одной из стрелок полосы прокрутки
Значение Value можно задать в момент конструирования, чтобы
при запуске приложения бегунок был установлен в необходимой пози¬
ции. Обычно Value устанавливают равным Minimum или Maximum,
чтобы бегунок находился в одном из крайних положений.
177
Значение Minimum и Maximum могут быть как положительны¬
ми, так и отрицательными.
Полосы прокрутки реагируют на уже рассмотренные события
Click, DoubleClick, Keypress, Enter, Leave, которые вызывают соот¬
ветствующие процедуры обработки этих событий (табл. 1.2).
Наиболее важные события линеек прокрутки указаны в табли¬
це 3.14.
Таблица 3.14 - События ScrollBar
Событие
Описание
Scroll
Генерируется один или более раз во время прокрутки содержимого
в ScrollBar, когда пользователь перемещает Thumb мышью
ValueChanged
Генерируется при изменении значения в диапазоне
Методы полос прокрутки не слишком важны и используются до¬
статочно редко.
Пример 3.9. Использование полос прокрутки
Откроем новую форму и разместим на ней два текстовых поля и
горизонтальную полосу прокрутки (рис. 3.13). Результат выполнения
события Change отображается в верхнем поле, события Scroll -
в нижнем.
Рисунок 3.13 - Пример программы с элементами HScrollBar
и VScrollBar
В окне свойств для объекта hScrollBar1 (имя присваивается по
умолчанию) задаем следующие значения свойств:
178
LargeChange = 10, Maximum = 100, Minimum = 0, SmallChange = 5.
Определим процедуры обработки событий
hScrollBar1_ValueChanged и hScrollBarl Scroll.
private void hScrollBarl_ValueChanged(object
sender, EventArgs e)
{
//Отображение в элементе textBoxl значения
//горизонтальной полосы прокрутки, когда
//происходит событие Change
textBoxl.Text =
hScrollBarl.Value.ToStringO;
}
private void hScrollBarl_Scroll(object sender,
ScrollEventArgs e)
{
//Отображение в элементе textBox2 значения
//горизонтальной полосы прокрутки, когда
//происходит событие Scroll
textBox2.Text =
hScrollBarl.Value.ToStringO;
}
3.16 Выводы
Приведены основные сведения, необходимые для разработки
простых приложений в Windows. Рассмотрены основные элементы
управления, использующиеся для создания графических интерфейсов,
их важнейшие свойства, методы и события. Эта информация является
достаточной для понимания назначения многих свойств и методов
различных дополнительных элементов управления. Именно поэтому
материал данного раздела будет полезен при изучении рассматривае¬
мых далее вопросов.
Приведенные примеры демонстрируют основные принципы ис¬
пользования различных элементов управления.
179
Материал раздела дает возможность:
- изучить основные элементы управления, размещенные на
панели инструментов, рассмотреть возможности их ис¬
пользования, получить опыт работы с этими элементами;
- получить информацию о свойствах элементов управления, об
их методах и событиях, которые используются при создании
приложений;
- приобрести опыт работы с формами, усвоить принципы
расположения элементов управления на них.
3.17 Вопросы для повторения и контроля знаний
1. Какие значения и свойства элемента Button необходимо за¬
дать, чтобы изменить цвет кнопки на красный?
2. Какое свойство необходимо изменить для элемента
RadioButton, чтобы внешне элемент стал похож на кнопку? В чем
различие между элементом RadioButton в виде кнопки и элементом
Button?
3. Почему не реализуется переход на элементы Label и
GroupBox?
4. На форме разместить 5 переключателей. При этом из первых
двух элементов образовать одну группу, из трех других - другую.
5. Как для элемента управления задать всплывающий текст?
6. Как изменить форму указателя мыши при наведении на за¬
данный элемент управления в режиме запуска проекта?
7. Какое свойство определяет режим ввода информации в тек¬
стовое поле TextBox в несколько строк?
8. Какие свойства определяют режим вывода информации в
элемент Label в несколько строк?
9. Как отобразить содержание списка элемента ListBox в три
колонки?
10. Как отсортировать значение списка элемента управления
ListBox?
180
11. Как организовать использование текстового поля TextBox
для ввода пароля? Что произойдет, если при этом свойство Multiline
будет значение true?
12. Измените размеры кнопки: ширина - 50, высота - 30.
13. Какое свойство позволяет не отображать значок формы в па¬
нели задач при сворачивании приложения?
14. Как организовать вызов процедуры Click для кнопки при
нажатии клавиш <Enter> или <Esc>?
15. Как ограничить количество вводимых в текстовое поле
TextBox символов?
16. Указать способы запрета ввода информации в текстовое поле
TextBox.
17. Организовать автоматическое изменение размеров элемента
PictureBox под загруженное изображение.
18. Какие свойства определяют диапазон перемещения бегунка
для элементов HScrollBar и VScrollBar?
19. Что определяет свойство Interval управляющего элемента
Timer?
3.18 Задания для самостоятельного решения
1. Написать процедуру обработки события изменения вида указа¬
теля мыши в зависимости от его расположения на форме. Например,
указатель имеет различную форму в каждом квадранте формы.
2. Написать процедуру обработки события: изменение размеров
формы должно приводить к тому, что ее ширина становится равной
половине экрана.
3. Разработать проект, в котором при нажатии кнопки мыши
происходит выделение в тексте управляющего элемента TextBox пяти
символов, которые добавляются в элемент ListBox или ComboBox.
4. Разместить на форме 3 кнопки и элемент "Текстовое поле", ко¬
торому после запуска проекта принадлежит фокус. При нажатии кла¬
виши <Esc> выполняется процедура Click первой кнопки, клавиши
<Enter> - процедура Click второй кнопки. Процедуры Click должны
выводить сообщение на форме о номере нажатой кнопки.
181
5. Написать процедуру обработки события, которая реализует
действия: при наведении указателя мыши на элемент он перемещает¬
ся в центр формы; при повторном наведении происходит возвращение
элемента на прежнее место.
6. Разработать проект, в котором при нажатии кнопки мыши сна¬
чала увеличиваются размеры элемента PictureBox вдвое, после до¬
стижения максимального значения, размеры уменьшаются, и т. п.
7. Разработайте проект, в котором:
- в элемент ListBox добавляется значение, выбранное в элемен¬
те ComboBox;
- по нажатию кнопки список в элементе ListBox очищается;
- положение элемента ListBox на форме задается вводом значе¬
ний в соответствующие текстовые поля;
- разрешение на изменение свойств элемента ListBox определя¬
ется элементом RadioButton.
8. Разработайте проект, в котором:
- изображение в элементе PictureBox изменяется выбором из
элемента ListBox;
- размер элемента PictureBox изменяется с помощью элементов
HScrollBar и VScrollBar (при этом рисунок остается вписан
в элемент управления);
- свойство Text элемента Label изменяется на название файла
с рисунком, отображаемым в элементе PictureBox.
9. Разработайте проект, в котором:
- размер шрифта элемента GroupBox изменяется выбором
из элемента ListBox;
- свойство Text элемента GroupBox, определяется выделенным
фрагментом в элементе TextBox;
- положение элемента GroupBox определяется элементами
HScrollBar и VScrollBar. При удержании мышки на бегунке
должно появляться значение установленной величины.
182
4 ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ
ПРОГРАММИРОВАНИЕ
4.1 Концепции объектно-ориентированного подхода
C# является полноценным объектно-ориентированным языком.
Программный код на C# представляет собой совокупность взаимо¬
действующих между собой объектов.
Основные принципы структурирования объектно-ориентирован¬
ного кода напрямую зависят от глубины анализа предметной задачи
и включают в себя следующие понятия.
Абстракция данных: подробности внутренней логики скрыты от
конечного пользователя. Пользователю не нужно знать, как работают
те или иные классы и методы, чтобы их использовать.
Наследование: возможность создавать новые определения клас¬
сов на основе существующих, расширяя и переопределяя их функци¬
ональность. Наследование используется для повторного использова¬
ния кода.
Инкапсуляция: механизм языка, позволяющий ограничить до¬
ступ одних компонентов программы к другим, охватывающий вопро¬
сы доступа к ним, их видимости.
Полиморфизм: поддержка выполнения нужного действия в за¬
висимости от типа передаваемого объекта. Применяется для универ¬
сальной обработки схожих объектов разных типов.
4.2 Классы и объекты
Класс представляет новый тип, который определяется пользова¬
телем.
Определение класса состоит из:
- определения атрибутов класса - информация, описывающая
объекты данного класса;
- методов класса - действия, которые либо могут выполнять
объекты данного класса, либо можно выполнять над
объектами данного класса.
183
Синтаксис описания класса:
[типДоступа] class имяКласса
{
[типДоступа] тип имяЭлементаКласса1;
[[типДоступа] тип имяЭлементаКласса2;]
[типДоступа] возвращаемыйТип
имяМетода1(спиокПараметров)
{
тело метода
}
}
Пример 4.1. Объявление класса Person
class Person
{
public string surname;
public string name;
public string patronymic;
public string gender;
public DateTime birth;
}
Объектом называется конкретный экземпляр определенного
класса, который позволяет получить доступ к его атрибутам и мето¬
дам. Для создания нового объекта в С# используется ключевое слово
new:
имяКласса имяОбъекта = new имяКласса]);
или
имяКласса имяОбъекта;
имяОбъекта = new имяКласса]);
//Фамилия
//Имя
//Отчество
//Пол
//Дата рождения
184
Пример 4.2. Создание объекта класса Person
Person р = new Person();
или
Person р;
р = new Person();
p.surname = "Петров";
p.name = "Игорь";
p.patronymic = "Сергеевич";
p.gender = "м";
p.birth = new DateTime(1975, 6, 11);
Ключевое слово new означает, что среде выполнения следует вы¬
делить необходимое количество оперативной памяти под создавае¬
мый объект. Выделение памяти производится из "управляемой кучи"
(managed heap).
В С# переменная любого класса - это ссылка на объект в памяти,
но не сам объект. При создании переменной используется конструк¬
тор класса.
Ключевое слово this представляет ссылку на текущий экземпляр
класса внутри его методов.
4.3 Методы класса
В предыдущих разделах рассматривались процедуры обработки
событий, которые в процессе выполнения программы инициирова¬
лись (запускались) в результате наступления определенного события
(щелчок мышью, нажатие клавиши и т. и.). C# имеет возможность
выделить неоднократно повторяющиеся фрагменты программы в
определенным образом организованные функциональные блоки опе¬
раторов, которые можно использовать без повторного написания и
отладки. Таким образом, сложные программы выходят более ком¬
пактными, а функциональные блоки при правильной организации мо¬
гут быть использованы в других программных разработках.
Поскольку C# является объектно-ориентированным языком вы¬
сокого уровня, то функциональные блоки организуются в виде проце¬
185
дур и функций, которые существуют только как методы определенно¬
го класса. Таким образом, любая программа на C# содержит хотя бы
один класс, а ее выполнение начинается с вызова основного метода:
[static] class Program
{
static void Main([аргументы])
{
//операторы и
//вызов методов
}
}
4.3.1 Методы-процедуры
Синтаксически метод, который реализует процедуру, определяет¬
ся как:
[модификаторДоступа] [static] void имяПроцедуры
([списокАргументов])
{
[блокОператоров]
}
где
- модификаторДоступа - один из возможных модификаторов
доступа (см. раздел 2.4);
- static - модификатор, который используется для объявления
статического члена класса, принадлежащего собственно
типу, а не конкретному объекту;
- имяПроцедуры - образуется соответственно общих правил
создания имен, но не может иметь описателей типа
(имяПроцедуры не возвращает значение);
- списокАргументов имеет следующий синтаксис:
[ref|out|params] типАргумента имяАргумента
где имяАргумента - имя переменной, массива (в случае массива ис¬
пользуется имяМассива[] без указания границ индексов, что позволя-
186
ет использовать одну процедуру для различного числа элементов мас¬
сива в каждом конкретном случае), элемента управления или формы;
типАргумента - любой встроенный тип данных или пользова¬
тельский класс;
out - определяет, что аргумент является для процедуры выход¬
ным, то есть принимает значение внутри процедуры;
ref - определяет, что аргумент передается в процедуру по ссылке;
params - позволяет передавать неопределенное количество па¬
раметров.
Необходимо обратить внимание, что параметр out должен быть
указан как в объявлении процедуры, так и при ее вызове.
СписокАргументов определяет связь с данными между процеду¬
рой, из которой происходит вызов, и вызываемым методом.
Локальные данные, определенные внутри метода, не могут ис¬
пользоваться в других методах (например, переменные с одинаковы¬
ми именами, но описанные в разных методах, сохраняются в разных
элементах памяти и их изменение в одном из методов не ведет к из¬
менениям одноименной переменной в другом методе).
Синтаксис оператора обращения к методу-процедуре следующий:
имяПроцедуры([списокЗначений]);
где списокЗначений - список значений аргументов (соответствует
списку аргументов в заголовке метода по количеству, последователь¬
ности и типу).
В теле метода-процедуры может быть использован оператор пе¬
редачи управления return для досрочного завершения ее выполнения.
Пример 4.3. Проект, реализующий изменение размеров прямо¬
угольника по значению масштабирующего коэффициента. Для зада¬
ния прямоугольников разработан пользовательский класс Rect с дву¬
мя полями: высота (height) и ширина (width).
Отображение прямоугольника осуществляется с помощью кон¬
тейнерного элемента управления Panel и задания ему границы
(BorderStyle = FixedSingle). Масштабирующий коэффициент вво¬
дится в элемент textBox1. Изменение размеров прямоугольника осу-
187
ществляется при нажатии на Командную кнопку. Указанные эле¬
менты управления подробно рассмотрены в разделе 3. Внешний вид
приложения представлен на рисунке 4.1.
//Файл Rect.cs
public class Rect
{
public float height;
public float width;
//Метод-процедура с аргументом -
//масштабирующим коэффициентом
public void Scale(float factor)
{
height *= factor;
width *= factor;
}
}
//Файл Forml.cs
public partial class Forml : Form
{
//Экземпляр пользовательского класса
Rect recti = new Rect();
//Метод-процедура класса формы для изменения
//размеров элемента управления Panel
private void drawRect()
{
pRect.Width = (int)rectl.width;
pRect.Height = (int)rectl.height;
}
public Forml()
{
InitializeComponent();
//Задание начальных размеров
//прямоугольника
188
rectl.width = (float)(this.Width -
(this.Width * 0.2));
rectl.height = (float)(this.Height -
(this.Height * 0.5));
//Задание подписей в элементах
//управления Label
label2.Text = "Ширина прямоугольника:
" + (int)rectl.width;
label3.Text = "Высота прямоугольника:
" + (int)rectl.height;
//Вызов метода-процедуры без параметров
//для формирования первоначального вида
//прямоугольника
drawRect();
}
private void buttonl_Click(object sender,
EventArgs e)
{
//Вызов метода Scale со значением
//масштабирующего коэффициента,
//полученным из текстового поля
rectl.Scale(float.Parse(textBoxl.Text));
//Вызов метода-процедуры без параметров
//для формирования вида измененного
//прямоугольника
drawRect();
}
}
Рисунок 4.1 - Результат выполнения программы
189
Пример 4.4. Метод формирования вектора из сумм элементов
столбцов матрицы
private static void sumMatrVector(float[,]
matrix, out float[] vector)
{
vector = new float[matrix.GetUpperBound(l)
+ 1];
//Цикл по элементам массива А и столбцам
//массива В
for (int j=0; j< vector.Length; j++)
{
vector[j] = 0;
//Цикл по строкам массива В
for (int i = 0; i <=
matrix.GetUpperBound(O); i++)
{
//Вычисление суммы
vector[j] += matrix[i, j];
}
}
}
Следует отметить, что при вызове метода необходимо соблюдать
соответствие между списками аргументов и значениями (табл. 4.1):
Таблица 4.1 - Соответствие между списками аргументов
и значениями
Аргумент
Значение
Переменная
Константа, переменная, элемент массива, выражение
Массив
Массив
Форма
Форма
Элемент управления
Элемент управления
Следующие примеры показывают правильное согласование
списков аргументов и значений.
190
Пример 4.5. Согласование списков аргументов и значений.
public static void sum(int A, int B, out int C)
{
//список аргументов состоит из переменных
С=А + В;
}
private void Form_Click(object sender, EventArgs
e)
{
//Объявление массива
int[] X = new int[3];
X[0] = 1;
X[l] = 2;
//список значений содержит элементы массива
//и выражение
sum(X[0], Х[0] + X[l], out Х[2]);
//Вывод результатов вычислений
//Преобразование целочисленных значений
//элементов массива X в строковое
//представление осуществляется неявным
//способом
MessageBox.Show("Pe3ynbTaT вычисления: " +
Х[0] + " + " + ( Х[0] +Х[1] ) + " = " +
Х[2]); }
private void Form_Click(object sender, EventArgs
e)
{
int x = 5, z;
//список значений содержит переменные и
//константу
sum(x, 4, out z);
//Вывод результатов вычислений
//Преобразование целочисленных значений
//в строковое представление осуществляется
//неявным способом
191
MessageBox.Show("Pe3yabTaT вычисления: " +
x +"+4 = "+z);
}
private static void sumMatrVector(float[,] В,
out string str)
{
//определение количества столбцов
int columnSize = B.GetUpperBound(l);
//объявление результирующего массива
float[] A = new float[columnSize + 1];
str = "";
//Цикл по
элементам массива
А и
столбцам
массива В
for (int j
{
A[j] =
//Цикл
=0; j < A.Length;
j++)
0;
по строкам массива
В
for
(int i =
0;
i <=
B.GetUpperBound(O); i++)
{
A[j] += B[i, j]; //Вычисление суммы
}
str += A[j].ToString() + "\t";
}
}
private void Form_Click(object sender, EventArgs
e)
{
//Объявление и инициализация массива В
float[,] B={{1,2,3},{4,5,6 } };
string str;
//Вызов пользовательской процедуры и
//передача аргументов
sumMatrVector(B, out str);
//Вывод результатов вычисления в окно
//MessageBox
MessageBox.Show("Pe3yabTaT вычисления: " +
str);
}
192
Поскольку методы sum и sumMatrVector никак не взаимодей¬
ствуют с атрибутами класса Forml, то они могут быть определены с
модификатором static. Результат выполнения программы отображает¬
ся в виде формы и показан на рисунке 4.2.
Рисунок 4.2 - Результат выполнения программы
4.3.2 Методы-функции
Синтаксически функция определяется следующим образом:
[модификаторыДоступа] [static] типРезультата
имяМетода([списокАргументов])
{
[операторыОбъявления]
[операторы]
return выражение;
}
Все элементы описания метода-функции аналогичны описанию
метода-процедуры, за исключением типРезультата.
Функция должна содержать хотя бы один оператор:
return выражение;
Пример 4.6. Добавим в пример 4.3 метод вычисления площади
прямоугольника по заданным значениям сторон. Значение площади
выводится в элементе управления Label при вызове метода отрисовки
прямоугольника.
//Файл Rect.cs
public class Rect
{
193
public float Area()
{
//Возвращаем вычисленное значение
//площади
return height * width;
}
}
//Файл Forml.cs
public partial class Forml : Form
{
Rect recti = new Rect();
private void drawRect()
{
pRect.Width = (int)rectl.width;
pRect.Height = (int)rectl.height;
label4.Text = "Площадь прямоугольника:
" + (int)rectl.Area();
}
}
Пример 4.7. Статический метод-функция для вычисления сред¬
него значения элементов одномерного массива
private static float sumVector(float[] A)
{
float sumVector = 0;
for (int i=0; i< A.Length; i++)
{
sumVector += A[i];
}
//Возвращаем вычисленное значение
return sumVector/A.Length;
}
194
Обращение к методу-функции может являться операндом выра¬
жения. Например, в операторе присваивания вызов метода будет вы¬
глядеть следующим образом:
имяПеременной = имяФункции([списокЗначений]);
Где списокЗначений - список значений аргументов (соответству¬
ет списку аргументов при объявлении метода по количеству, после¬
довательности и типу).
Так в примере 4.6 вызов метода rect1.Area() является операндом
выражения:
label4.Text = "Площадь прямоугольника: " +
(int)rectl.Area();
Кроме того, необходимо соблюдать соответствие между списка¬
ми аргументов и значениями (табл. 4.1).
Пример 4.8. Сохранение результата вычисления метода в пере¬
менной и использование произвольного количества параметров
public static float summa(params float[] A)
{
float s=0;
//Цикл для каждого элемента массива
foreach (float el in A)
{
s += el; //Вычисление суммы
}
return s;
}
private void Form_Click(object sender, EventArgs
e)
{
float sum = summa(12, 5, -3, 1, 8);
//Вывод результатов вычислений
MessageBox.Show("Pe3yHbTaT вычисления: " +
sum);
}
195
4.3.3 Передача аргументов методу по ссылке
по значению
Передача значений аргументов при вызове метода по ссылке
означает, что передается адрес памяти, где сохраняется значение ар¬
гумента. То есть метод для работы с переданным по ссылке аргумен¬
том использует тот же элемент (область) памяти, что и вызывающая
его процедура или функция. При этом не выделяется дополнительная
память для работы с переданным аргументом. Изменение значения в
методе, к которому было осуществлено обращение, означает измене¬
ние значения аргумента в вызывающей процедуре или в функции (ис¬
пользуется тот же элемент или область памяти).
Передача параметра по значению в C# определена по умолчанию.
Изменения значения такого аргумента в методе не ведут к изменени¬
ям аргумента в вызывающей процедуре или в функции. Указанный
механизм объясняется тем, что при передаче по значению метод по¬
лучает не саму переменную, а ее копию. Это удобно, если модифика¬
ция данных необходима только внутри вызываемой процедуры или
функции и нет необходимости передавать измененные данные обрат¬
но в метод, из которого был сделан вызов.
При передаче параметра по ссылке метод получает адрес пере¬
менной в памяти (в списке аргументов метода для переданного таким
способом аргумента используется ключевое слово ref). В данном слу¬
чае, если в методе изменяется значение параметра, передаваемого
по ссылке, то его значение изменяется и вызывающей процедуре.
4.3.4 Использование форм и элементов управления
как аргументов методов
Список аргументов методов может содержать имена форм
и элементов управления (описатель типа Form и производные
от Controls: TextBox, RadioButton и т. д.). Это позволяет создавать
универсальные алгоритмы для работы с формами и элементами
управления.
196
Пример 4.9. Использование элемента управления как аргумента
метода
Для привлечения внимания пользователя к одной из кнопок
управления формы можно создать одну универсальную процедуру,
которая меняет шрифт и цвет фона.
private void btnAttantion(Button btn)
{
//Для формирования нового шрифта берутся
//данные о старом шрифте и добавляется
//наклонный стиль
btn.Font = new Font(btn.Font,
FontStyle.Italic);
btn.BackColor = Color.Red; //для установки
//красного цвета
//фона кнопки
//используется
//перечисление цветов
}
Аргументом метода является кнопка. Обращение к данному ме¬
тоду с указанием имени любой конкретной кнопки, приведет к изме¬
нению шрифта и цвета кнопки (указывается имя кнопки buttonl).
btnAttantion(buttonl);
Для контроля соответствия переданных при обращении типов
форм и элементов управления в C# может быть использован специ¬
альный оператор is:
if (имяОбъекта is типОбъекта)
{
//выполнение действий, если объект
//соответствует типу
}
4.3.5 Конструктор класса
Конструктор класса представляет собой метод с именем, совпа¬
дающим с именем класса, и не возвращающий никакого значения.
В классе могут быть определены несколько конструкторов, принима¬
ющие разное количество параметров.
197
Если в классе явно не определен конструктор, то компилятор ав¬
томатически создает конструктор по умолчанию без параметров, в ко¬
тором данные класса получают значения по умолчанию.
Конструктор по умолчанию без параметров может быть также
явно определен в классе.
В случае, когда конструктор не инициализирует значения полей
объекта, то они получают значения по умолчанию. Для переменных
числовых типов это число 0, а для типа string и классов - это значе¬
ние null.
Пример 4.10. Создание конструкторов
class Person
{
public string surname;
public string name;
public string patronymic;
public string gender;
public DateTime birth;
//Конструктор 1
public Person!)
{
surname = "Неизвестно";
gender = "m";
}
//Конструктор 2
public Person(string sname)
{
surname = sname;
gender = "m";
}
//Конструктор 3
public Person(string sname, string g)
{
surname = sname;
gender = g;
}
}
//Фамилия
//Имя
//Отчество
//Пол
//Дата рождения
198
Пример 4.11. Вызов конструкторов
//вызов первого конструктора без параметров
Person pi = new Person();
//вызов второго конструктора с одним параметром
Person р2 = new Регзоп("Сидоров");
//вызов третьего конструктора с двумя
//параметрами
Person р2 = new Регзоп("Иванова", "ж");
Ключевое слово this представляет ссылку на текущий экземпляр
класса.
Пример 4.12. Использование ключевого слова this
class Person
{
public string surname;
public string name;
public string patronymic;
public string gender;
public DateTime birth;
//Фамилия
//Имя
//Отчество
//Пол
//Дата рождения
public Person() : this("Hen3BecTHo")
{
}
//Обращение к третьему конструктору
public Person(string surname) : this
(surname, "м")
{
}
//Разграничение параметров и полей класса
public Person(string surname, string gender)
{
this.surname = surname;
//this.gender - поле класса
//gender - параметр
this.gender = gender;
}
}
199
4.3.6 Перегрузка методов
Перегрузка методов - это объявление в классе методов с одина¬
ковыми именами, но с различными параметрами. В C# можно созда¬
вать в классе несколько методов с одним и тем же именем, но разной
сигнатурой.
Сигнатура складывается из следующих аспектов:
- имя метода;
- количество параметров;
- типы параметров;
- порядок параметров;
- модификаторы параметров.
Названия параметров в сигнатуру не входят.
Например, сигнатура метода из примера 4.5 будет
sum(int, int, out int);
При перегрузке операций сигнатура методов может отличаться
по всем аспектам, кроме имени.
Пример 4.13. Перегрузка методов
class Calculator
{
public int Sum(int a, int b)
{
return a + b;
}
public int Sum(int a, int b, int c)
{
return a+b+ c;
}
public int Sum(int a, int b, int c, int d)
{
return a+b+c+d;
}
public double Sum(double a, double b)
{
return a+b;
}
}
200
Сигнатуры методов примера:
Sum(int, int)
Sum(int, int, int)
Sum(int, int, int, int)
Sum(double, double)
Пример 4.14. Использование перегруженных методов. Результа¬
ты вычисления сумм отображаются на форме в элементе управления
ListBox (рис. 4.3). Нюансы применения метода Items.Add() рассмот¬
рены в пункте 3.9.
//класс формы
public partial class Forml : Form
{
public Forml()
{
InitializeComponent();
Calculator calc = new Calculator();
listBoxl
.Items.Add(
"1
+
2 = "
+
calc.Sum(l,
2)); //3
listBoxl
.Items.Add(
"1
+
2
+ 3 = "
+
calc.Sum(l,
2, 3)); //
6
listBoxl
.Items.Add(
"1
+
2
+ 3 + 4 =
»!
+ calc.Sum(l
, 2, 3, 4))
f
II
10
listBoxl
.Items.Add(
"1
.4
+
2.5 = "
+
calc.Sum(1.4
, 2.5)); II
3
.9
}
}
Рисунок 4.3 - Результат перегрузки операций
201
Перегружаемые методы могут отличаться по используемым мо¬
дификаторам доступам.
4.4 Класс Object
В С# все типы данных (как структурные, так и ссылочные) явля¬
ются производными от класса Object.
Определение класса Object:
public class Object
{
public Object();
public virtual bool Equals(object ob);
public virtual int GetHashCode();
public Type GetType();
public virtual string ToString();
protected Finalize();
protected object MemberwiseClone();
public static bool ReferenceEquals(object
objA, object objB);
}
Характеристики методов класса Object приведены в таблице 4.2.
Таблица 4.2 - Характеристики методов класса Object
Метод
Назначение
Equals
Выполняет проверку того, что сравниваемые объекты равны
GetHashCode
Возвращает целое число, идентифицирующее конкретный
объект данного типа
GetType
Возвращает описание типа того объекта, для которого
он был вызван
ToString
Возвращает строковое представление объекта
Finalize
Вызывается перед удалением объекта
MemberwiseClone
Используется для создания еще одной ссылки на область
памяти, занимаемую данным объектом
ReferenceEquals
Выполняет проверку того, что сравниваемые объекты
указывают на одну итуже область памяти
202
4.5 Пространства имен
Для улучшения структурирования программного кода в C# ис¬
пользуются пространства имен. Объявление пространства имен осу¬
ществляется следующим образом:
namespace имяПространстваИмен
{
//определения типов
}
Обращение к типу, объявленному в пространстве имен, реализу¬
ется с помощью конструкции:
имяПространстваИмен.тип
Пространства имен могут быть вложенными.
Для подключения классов из какого-либо пространства имен ис¬
пользуется конструкция
using имяПространстваИмен
Если подключено пространство имен, то можно ссылаться на тип
и без указания пространства имен.
4.6 Реализация наследования
Синтаксис классического наследования в C#:
class классПотомок : классРодитель
{
}
Язык C# не поддерживает множественное наследование. Для вы¬
зова в конструкторе класса-потомка конструктора класса-родителя
используется ключевое слово base.
class классПотомок : классРодитель
{
классПотомок(аргументы) : Ьазе(аргументы)
{
}
}
203
Пример 4.15. Наследование от класса Person
Класс, наследующий студента от базового класса Person.
class Student : Person
{
}
Класс Student наследует все свойства, методы, поля, которые
есть в классе Person. При наследовании не передаются конструкторы
базового класса.
Person p = new Person("MopryHOB");
p = new Student("KMpeeB");
Поскольку в C# все классы наследуются от базового класса
Object, классы Person и Student кроме своих собственных методов,
также будут иметь и методы класса Object: ToString(), Equals(),
GetHashCode(), GetType() и другие.
При создании производного класса нужно учитывать тип доступа
к базовому классу. Тип доступа к производному классу должен быть
таким же, как и у базового класса, или более строгим. Если базовый
класс имеет тип доступа internal, то производный класс может иметь
тип доступа internal или private, но не public.
Пример 4.16. Использование ключевого слова base
class Student : Person
{
public string NRecord { get; set; }
public Student(string sname, string
nzachet) : base(sname) //Передача sname
//конструктору базового
//класса Person
{
NRecord = nzachet;
}
}
Person p = new Регзоп("Андреев");
Student p = new Student("neTpoB", "001/20");
204
4.7 Особенности инкапсуляции
Для реализации инкапсуляции в языке C# используются модифи¬
каторы доступа (см. пункт 2.4) и свойства.
Пример 4.17. Использование разных модификаторов доступа
public class MathVariable
{
int а; //аналогично private int a;
//поле b доступно только из текущего класса
private int b;
//с доступно из текущего класса и
//производных классов
protected int с;
//d доступно в любом месте сборки
internal int d;
//е доступно в любом месте сборки и из
//классов-наследников
protected internal int е;
//f доступно в любом месте программы, а
//также для других программ и сборок
public int f;
//g доступно из текущего класса и
//производных классов, которые определены в
//том же проекте
protected private int g;
public string genText_a()
{
return string.Format($"nepeMeHHaH a =
{a}");
}
internal string genText_b()
{
205
return string.Format($"nepeMeHHan b =
{b}");
}
protected string genText_e()
{
return string.Format($"nepeMeHHan e =
{e}");
}
private string genText_f()
{
return string.Format($"nepeMeHHan f =
}
}
//класс формы
public partial class Forml : Form
{
MathVariable var = new MathVariable();
public Forml()
{
InitializeComponent();
//присвоить значение переменной
//невозможно, так как она закрыта и
//класс Forml ее не видит
var.a = 4; //Ошибка, получить доступ
//нельзя
//аналогично для переменной b
var.b = 3; //Ошибка, получить доступ
//нельзя
//класс Forml не является классом-
//наследником класса MathVariable
var.c = 1; //Ошибка, получить доступ
206
//нельзя
//переменная d с модификатором
internal
//доступна из любого места сборки,
//поэтому при присвоении ей значения,
//ошибка не возникает
var.d = 1;
//переменная так же
//доступна из любого места программы
var.e = 8;
//переменная f общедоступна
var.f = 8;
private void Forml_Load(object sender, EventArgs
{
//Вывод значений переменных
//Поскольку метод genText_f объявлен с
//модификатором private, он может быть
//использован только внутри класса
//MathVariable
labell.Text = var.genText_f(); //Ошибка,
//получить
//доступ
//нельзя
//так как метод объявлен с модификатором
//protected, а класс Forml не является
//наследником класса MathVariable
label2.Text = var.genText_e(); //Ошибка,
//получить
//доступ
//нельзя
//Общедоступный метод
label3.Text = var.genText_a();
//Метод доступен из любого места сборки
label4.Text = var.genText_b();
}
207
4.8 Свойства класса
Свойство - это член класса, предоставляющий гибкий механизм
для чтения, записи или вычисления значения поля. Оно позволяет ор¬
ганизовать доступ к внутреннему состоянию объекта, который ими¬
тирует поле.
Обращение к свойству объекта выглядит так же, как и обращение
к полю, но, в действительности, реализовано через вызов функции.
При попытке задать значение свойства вызывается метод, назы¬
ваемый сеттером (setter), а при попытке получить значение свойства -
геттер (getter). Как правило, свойство связано с некоторым внутрен¬
ним полем объекта.
Синтаксис определения свойства класса:
[модификаторДоступа] возвращаемыйТип
названиеСвойства
{
//код свойства
}
Пример 4.18. Определение свойства
class Person
{
}
private string sname;
public string Sname
{
get
{
return sname;
}
set
{
sname = value;
}
}
208
Пример 4.19. Использование свойства
Person pi = new Person();
//при установке значения свойства срабатывает
//блок set, значение "Степанова" - передаваемое
//в свойство value
p.Name = "Степанова";
//при получении значения свойства и присваивании
//его значения переменной, срабатывает блок get
string plName = pl.Sname;
Пример 4.20. Определение свойства только для чтения и только
для записи
class Person
{
private string sname;
//Свойство только для чтения
public string Sname
{
get
{
return sname;
}
}
private string gender;
//Свойство только для записи
public string Gender
{
set
{
gender = value;
}
}
}
209
Пример 4.21. Использование модификаторов доступа при созда¬
нии свойств
class Person
{
private string sname;
public string Sname
{
get
{
return sname;
}
private set
{
sname = value;
}
}
public Person(string sname, string gender)
{
Sname = sname;
Gender = gender;
}
}
Person pi = new Регзоп("Матвеенко", "ж");
//Ошибка, поскольку блок set объявлен с
//модификатором private
pl.Sname = "Сергеев";
Модификатор доступа для блока set или get можно установить,
если свойство имеет оба блока (и set, и get). Только один блок set или
get может иметь модификатор доступа, но не оба сразу.
Модификатор доступа блока set или get должен быть более огра¬
ничивающим, чем модификатор доступа свойства. Например, если
210
свойство имеет модификатор public, то блок set/get может иметь
только модификаторы protected internal, internal, protected, private.
В случаях, когда блоки get и set присваивают значение резервно¬
му полю или извлекают значение из него без включения дополни¬
тельной логики, в C# могут использоваться автоматические свойства.
Если у свойства есть блоки get и set, они оба должны быть авто¬
матически реализованы. Автоматически реализуемое свойство опре¬
деляется с помощью ключевых слов get и set без указания реализа¬
ции, что значительно улучшает удобочитаемость программного кода.
Пример 4.22. Использование автоматических свойств
class Person
{
public string Surname { get; set; }
public string Name { get; set; }
public string Patronymic { get; set; }
public string Gender { get; set; }
public DateTime Birth { get; set; }
public Person(string sname, string gender)
{
Sname = sname;
Gender = gender;
}
}
4.9 Индексаторы
Индексаторы позволяют индексировать объекты и обращаться к
данным по индексу. Они дают возможность работать с объектами как
с массивами.
По форме напоминают свойства со стандартными блоками get
и set, которые возвращают и присваивают значение.
Синтаксис индексатора:
возвращаемыйТип this [тип праметр1, ...]
{
get
211
{
}
set
{
}
}
В отличие от свойств индексатор не имеет названия. Вместо
названия указывается ключевое слово this, после которого в квадрат¬
ных скобках идут параметры. Индексатор должен иметь как минимум
один параметр.
Пример 4.23. Использование индексатора. Расширение массива
объектов осуществляется с использованием метода Array.Resize()
(см. п. 2.8.4).
class Students
{
private Student[] data;
public Students()
{
data = new Student[0];
}
//Метод добавления студента с увеличением
//размера массива
public void add(Student student)
{
Array.Resize(ref data, data.Length +
i);
data[data.Length - 1] = student;
}
//индексатор
public Student this[int index] //способ
//доступа к
//элементам
//индексатора
{
212
get
{
//Хранение всех объектов Student в
//массиве data
return data[index];
}
set
{
data[index] = value;
}
}
}
Students students = new Students();
Student s = new Student("MaKeeB", "Петр",
"Сидорович", "001");
students.add(s);
students.add(new Student("Mиxaйлoв", "Егор",
"Константинович", "005"));
Student s = students[0];
4.10 Виртуальные методы и свойства
В случае необходимости изменить в классе-наследнике функцио¬
нал метода, который был унаследован от базового класса, класс-
наследник может переопределять методы и свойства базового класса.
Для реализации полиморфизма, основанного на виртуальных ме¬
тодах, в языке C# используются ключевые слова virtual и override.
Методы и свойства, которые необходимо сделать доступными
для переопределения, в базовом классе помечаются модификатором
virtual и называются виртуальными.
Для того, чтобы переопределить метод в классе-наследнике, он
определяется с модификатором override. Переопределенный метод в
классе-наследнике должен иметь тот же набор параметров, что и вир¬
туальный метод в базовом классе.
213
class классРодитель
{
virtual метод(аргументы)
{
}
}
class классПотомок : классРодитель {
override метод(аргументы)
{
}
}
Пример 4.24. Использование виртуального метода
В примере реализуется переопределение виртуального метода
Object.ToString() (см. пункт 4.4). Результат выполнения отображает¬
ся в элементе управления ListBox (рис. 4.4).
class Person
{
public string Surname { get; set; }
public string Name { get; set; }
public string Patronymic { get; set; }
public string Gender { get; set; }
public DateTime Birth { get; set; }
public Person(string sname, string name,
string patr)
{
Surname = sname;
Name = name;
Patronymic = patr;
}
public override string ToStringO
{
if ((Name != null) && (Patronymic !=
null))
{
return Surname + " " +
Name.Substring(0, 1) + " . " +
Patronymic.Substring(0, 1) +"
214
»! .
}
else return
}
}
class Student : Person
{
public string NRecord { get; set; }
public Student(string sname, string name,
string patr, string nrec) : base(sname, name,
patr) //Передача sname конструктору базового
//класса Person
{
NRecord = nrec;
}
}
//класс формы
public Forml()
{
InitializeComponent();
Person pi = new Регзоп("Иванов", "Петр",
"Сидорович");
// вызов метода ToString из класса Person
lbStudents.Items.Add(pl.ToStringO);
Student р2 = new Student("CeMeHOB", "Егор",
"Константинович", "005");
// вызов метода ToString из класса Person
lbStudents.Items.Add("CTyfleHT: " +
p2.ToString());
}
215
Рисунок 4.4 - Результат использования виртуального метода
4.11 Скрытие методов и свойств
Изменить функциональность метода можно как с помощью меха¬
низма переопределения виртуального метода, так и с помощью
скрытия невиртуального метода. Следует отметить, что скрытие не
дает выполняться полиморфизму.
При скрытии в производном классе определяется член с таким же
именем и сигнатурой, как и у члена в базовом классе. В таком случае
член базового класса будет скрыт, а в производном классе такой член
должен быть объявлен с использованием ключевого слова new. В
данном случае ключевое слово new не имеет отношения к созданию
объекта, а используется как модификатор.
Пример 4.25. Скрытие метода
class Person
{
public string surname = "Иванов";
public string Print()
{
return "Человек " + surname;
}
}
class Student : Person
{
public new string Print()
216
{
return "Студент " + surname;
}
}
Student s = new Student();
Person p=s;
string st;
st = s.Print(); //Содержит "Студент Иванов"
st = p.Print(); //Содержит "Человек Иванов"
В примере несмотря на то, что s и p указывают на один объект,
результат вызова метода Print() будет зависеть от типа переменной,
ссылающейся на объект. Если бы вместо скрытия использовался ме¬
ханизм виртуальных методов, то содержимое переменной st было бы
одинаковым.
Для обращения к реализации скрытого члена базового класса ис¬
пользуется ключевое слово base.
4.12 Частичные классы
Понятие «Частичные классы» является специфическим для языка
C# и позволяет определить один класс в нескольких файлах. Указа¬
ние, что класс является частичным, осуществляется с помощью мо¬
дификатора partial. Следует отметить, что указанное ключевое слово
встречалось в некоторых рассмотренных примерах. При построении
проектов Windows Forms класс формы по умолчанию является ча¬
стичным и располагается в двух файлах.
Пример 4.26. Использование частичных классов
Например, класс формы Form1 из примера 4.8 описан в фай¬
лах Form1.Designer.cs и Form1.cs (рис. 4.5). При этом код
Form1.Designer.cs генерируется автоматически и содержит следую¬
щее описание класса:
namespace MethodsRect
{
partial class Forml
{
217
// Код, автоматически созданный
//конструктором форм Windows
private void InitializeComponent()
{
this.buttonl = new
System.Windows.Forms.Button();
this.pRect = new
System.Windows.Forms.Panel();
this.labell = new
System.Windows.Forms.Label() ;
this.textBoxl = new
System.Windows.Forms.TextBox();
this.label2 = new
System.Windows.Forms.Label();
this.label3 = new
System.Windows.Forms.Label();
this.label4 = new
System.Windows.Forms.Label();
Обозреватель решений
- П X
(й в! - # Ь ' 5 6 i И
<>>0
Обозреватель решений — поиск (Ctrl+;)
P-
Решение "MethodsRect" (проектов: 1)
л [с*] MethodsRect
t> Properties
> Ссылки
yil App.config
л H Form1.cs
> Form1.Designer.es
"Й Forml.resx
> c« Program.es
t> c* Reet.cs
Рисунок 4.5 - Расположение частичных классов в разных файлах
В файле Form1.cs описание класса продолжается следующим об¬
разом:
218
namespace MethodsRect
{
public partial class Forml : Form
{
//Элементы класса Forml
Rect recti = new Rect();
public Forml()
{
InitializeComponent();
4.13 Абстрактные классы и члены классов
4.13.1 Абстрактные классы
Абстрактный класс - это базовый класс, в котором определяется
самая общая форма для всех его производных классов. Конкретизация
общей формы и ее наполнение деталями осуществляется в производ¬
ных классах. В абстрактном классе определяется сигнатура методов,
которые необходимо реализовать в производных классах.
Абстрактный класс может иметь переменные, методы, конструк¬
торы, свойства. При определении абстрактных классов используется
ключевое слово abstract.
Одной из основных особенностей абстрактного класса являет¬
ся невозможность использования конструктора для создания его
объекта.
Пример 4.27. Описание абстрактного класса
Все объекты в примере будут представлять либо студента, либо
преподавателя (т. е. напрямую от класса Person объекты создаваться
не будут). Поэтому имеет смысл сделать его абстрактным.
abstract class Person
{
public string Surname { get; set; }
public string Name { get; set; }
public string Patronymic { get; set; }
219
public string Gender { get; set; }
public DateTime Birth { get; set; }
public Person(string sname, string name,
string patr)
{
Surname = sname;
Name = name;
Patronymic = patr;
}
public override string ToStringO
{
if ((Name != null) && (Patronymic !=
null))
{
return Surname + " " +
Name.Substring(0, 1) + " . " + Patro-
nymic.Substring(0, 1) +
}
else return
}
}
class Student : Person
{
//Автосвойство с номером зачетной книжки
public string NRecord { get; set; }
public Student string sname, string name,
string patr, string nzachet) : base(sname,
name, patr) //Передача параметров конструктору
//базового класса Person
{
NRecord = nrec;
}
}
class Teacher: Person
{
220
//Должность
public string Position { get; set; }
public Teacher(string sname, string name,
string patr, string position) : base(sname,
name, patr) //Передача параметров конструктору
//базового класса Person
{
Position = position;
}
}
Пример 4.28. Использование абстрактного класса
В примере используется форма и набор элементов управления из
примера 4.27. Результат использования классов, производных от аб¬
страктного, приведен на рисунке 4.6.
public partial class Formi : Form
{
public Forml()
{
InitializeComponent();
Student student = new Student("Maтвeйчyк",
"Сергей", "Сидорович", "005");
Teacher teacher = new
ТеасЬег("Александров", "Игорь",
"Матвеевич", "Старший преподаватель");
//вызов метода ToString из класса
//Person
lbStudents.Items.Add("CTyfleHT: " +
student.ToStringO);
//вызов метода ToString из класса
//Person
lbStudents.Items.Add("Преподаватель:
" + teacher.ToStringO);
221
Рисунок 4.6 - Использование абстрактного класса
4.13.2 Абстрактные члены классов
Кроме обычных свойств и методов абстрактный класс может
иметь абстрактные члены классов. Функционал абстрактных членов
классов должен быть определен не в базовом абстрактном классе,
а в производных от него. Для определения абстрактных членов класса
также используется ключевое слово abstract. В C# абстрактными мо¬
гут быть: методы, свойства, индексаторы и события.
Абстрактные члены классов не могут быть описаны с использо¬
ванием модификатора private.
В производном классе должны быть переопределены и реализо¬
ваны все абстрактные методы и свойства, которые объявлены в базо¬
вом абстрактном классе. Если базовый класс имеет хотя бы один абс¬
трактный член класса, то этот класс должен быть определен как абст¬
рактный.
Переопределение в производном классе осуществляется с помо¬
щью модификатора override (см. п. 4.10).
Пример 4.29. Использование абстрактного метода
Для расширения функционала примера 4.6 создадим базовый
класс Shape, который позволит описывать и вычислять площадь не
только прямоугольников.
abstract class Shape
{
public abstract float Area();
}
222
class Rect : Shape
{
public float height;
public float width;
public override float Area()
{
//Возвращаем вычисленное значение
//площади
return height * width;
}
}
class Circle : Shape
{
public float radius;
public override float Area()
{
//Возвращаем вычисленное значение
//площади
return (float)Math.PI * radius * radius;
}
}
Определение абстрактных свойств похоже на определение авто¬
свойств.
Пример 4.30. Использование абстрактных свойств
Результаты использования абстрактных свойств приведены на
рисунке 4.7.
abstract class Person
{
public abstract string Surname { get; set;
}
}
class Teacher : Person
{
public string Position { get; set; }
223
private string surname;
public override string Surname
{
get
{
return Position +", "+ surname;
}
set
{
surname = value;
}
}
class Student : Person
{
private string surname;
public override string Surname { get; set;
}
}
Рисунок 4.7 - Использование абстрактных свойств
4.14 Интерфейсы
Интерфейс представляет собой ссылочный тип, который опреде¬
ляет набор методов и свойств, однако не реализует их. Функционал
интерфейсов реализуют классы и структуры, которые наследуют дан¬
ные интерфейсы.
224
Для определения интерфейса используется ключевое слово
interface.
Названия интерфейсов в C# принято начинать с заглавной бук¬
вы I, например, IComparable, IEnumerable и т. д.
Например, интерфейс IFilelOOperations:
public interface IFilelOOperations
{
void readFile(string pathFile);
void writeFile(string pathFile);
}
Для объявления интерфейса используется следующий синтаксис:
[спецификаторы] interface имяИнтерфейса
{
типВозврата имяМетода1(списокПараметров);
типВозврата имяМетода2(списокПараметров);
//...
типВозврата имяМетодаЫ(списокПараметров);
}
Синтаксис класса, который реализует интерфейс:
class имяКласса : имяИнтерфейса
{
//тело класса
}
Для интерфейсов могут быть указаны спецификаторы: new,
public, protected, internal, private. Спецификатор new применяется
для вложенных интерфейсов и аналогичен модификатору new для ме¬
тода класса.
У интерфейса методы и свойства не имеют реализации, в этом
они аналогичны абстрактным методам абстрактных классов.
При объявлении интерфейса все его члены - методы и свойства
не имеют модификаторов доступа, но фактически по умолчанию они
имеют доступ public, так как цель интерфейса - определение функ¬
ционала для реализации его классом. Поэтому весь функционал дол¬
жен быть открыт для реализации.
225
Интерфейсы могут определять такие программные сущности, как
методы, свойства, индексаторы и события. Однако интерфейсы не мо¬
гут определять статические члены, переменные и константы.
В Visual Studio есть специальный компонент для добавления нового
интерфейса в отдельном файле. Для добавления интерфейса в проект не¬
обходимо нажать правой кнопкой мыши на проект и в появившемся кон¬
текстном меню выбрать «Добавить» -> «Компонент» и в диалоговом ок¬
не добавления нового компонента выбрать пункт Interface (рис. 4.8).
При реализации интерфейса учитываются методы и свойства,
унаследованные от базового класса. Если класс одновременно насле¬
дует другой класс и реализует интерфейс, то название базового класса
должно быть указано до реализуемых интерфейсов.
C# не поддерживает множественное наследование, но класс мо¬
жет реализовать сразу несколько интерфейсов, что позволяет частич¬
но обойти указанное ограничение.
Рисунок 4.8 - Добавление нового интерфейса в Visual Studio
Все реализуемые интерфейсы указываются через запятую:
классПотомок : имяИнтерфейсаФ, имяИнтерфейса2,
имяИнтерфейсаЭ...
{
}
226
Пример 4.31. Применение интерфейса для реализации множе¬
ственного наследования
interface IShape
{
float Area();
float Perimeter();
}
interface IColourable
{
Color getBackColor();
}
class Trapezoid :
{
public float
public float
public float
public float
IShape,
a;
b;
c;
d;
IColourable
public float Area()
{
//Возвращаем вычисленное значение
//площади
return ( а + b ) / 2 * (float)Math.Sqrt(
с * с - Math.Pow((Math.Pow(( b - a), 2) + c
*c - d*d)/(2* (b - a)), 2));
}
public float Perimeter()
{
//Возвращаем вычисленное значение
//периметра
return а + b + с + d;
}
public Color getBackColor()
{
return Color.Blue;
}
}
227
4.15 Выводы
Рассмотрены основные концепции объектно-ориентированного
программирования. Выделены нюансы применения приемов объект¬
но-ориентированного программирования в C#. Приведенные примеры
позволяют разобрать и отработать аспекты применения объектно¬
ориентированного программирования в контексте визуального.
Рассмотренный материал дает возможность:
- изучить основные принципы объектно-ориентированного
программирования, рассмотреть возможности их использова¬
ния;
- получить информацию о правилах формирования методов,
которые используются при создании приложений;
- получить опыт создания структуры приложения с использова¬
нием рассмотренных концепций.
4.16 Вопросы для повторения и контроля знаний
1. Из каких секций состоит описание класса?
2. Как выполняется объявление класса?
3. Как определить доступность элемента класса?
4. Что такое данные-члены, где и как они могут объявляться?
5. Что такое методы, где и как они могут объявляться?
6. Как организовать доступ к атрибуту класса из класса формы?
7. В чем заключается понятие наследования?
8. Как выглядит объявление производного класса?
9. Что такое спецификаторы доступа, как они используются?
10. Какиечленыкласса ненаследуются?
11. Как строится конструктор производного класса?
4.17 Задания для самостоятельного решения
1. Опишите класс «Прямоугольник», объект которого может быть
задан с помощью: двух сторон; величины диагоналей и угла между
ними; длины одной стороны и диагонали. Напишите метод, который
вычисляет его площадь.
228
2. Напишите метод определения максимального значения среди
неопределенного количества значений.
3. Для задания 9 из раздела 2 разработать методы определения
минимального и максимального элементов, а также вычисления гео¬
метрического среднего.
4. Для задания 10 из раздела 2 разработать метод для формирова¬
ния массива.
5. Построить иерархию классов: рабочий, кадры, инженер, адми¬
нистрация. Реализовать вывод данных для объектов каждого класса
иерархии с использованием виртуальных методов.
6. Построить иерархию классов: место, область, город, мегапо¬
лис. Реализовать вывод данных для объектов каждого класса иерар¬
хии с использованием виртуальных методов.
229
БИБЛИОГРАФИЧЕСКОЕ ОПИСАНИЕ
1. Албахари Дж. C# 6.0. Справочник. Полное описание языка
[Текст] / Дж . Албахари, Б. Албахари - 6-е изд. - Москва: Вильямс,
2016.- 1040 с.
2. Биллиг В. А. Основы объектного программирования на C#
(C# 3.0, Visual Studio 2008) [Текст]: учебное пособие / В. А. Биллиг. -
Москва: Интернет-университет информационных технологий, Бином.
Лаборатория знаний, 2016.-584 с.
3. Ватсон К. C# / К. Ватсон ; К. Ватсон ; пер. с англ. И. Штерева. -
М. : Лори, 2005. - 861с. - Перевод изд.: Beginning С#/ K.Watson
4. Ватсон, Б. C# 4.0 на примерах / Б. Ватсон ; Б. Ватсон ; пер. с
англ. С. Иноземцева ; гл. ред. Е. Кондукова. - СПб. : БХВ-Петербург,
2011.- 608с. : ил. - Перевод изд.: C# 4/0 How-to/B. Watson. -
5. Климов, А.П. C# : советы программистам / А. П. Климов ;
А.П. Климов. - СПб.: БХВ-Петербург, 2008. - 544с.: ил. + 1 CD-ROM.
6. Ишкова Э. А. С#. Начала программирования : учебник для ву¬
зов / Э. А. Ишкова ; Э. А. Ишкова. - М. : Бином-Пресс, 2007. - 336 с. :
ил.
7. Павловская Т. А. С#. Программирование на языке высокого
уровня : учебник для вузов / Т. А. Павловская ; Т. А. Павловская. -
СПб. : Питер, 2007. - 432с. : ил. - (Учебник для вузов).
8. Робисон, У. C# без лишних слов / У. Робисон ; У. Робинсон ;
пер. с англ. А. А. Слинкина. - М. : ДМК Пресс, 2002. - 352с. : ил. - (Для
программистов). - Перевод изд.: Pure C#/by W. Robison.
9. Скит, Д. С#: программирование для профессионалов [Элек¬
тронный ресурс] = J. Skeet. C# in depth / Д. Скит ; Д. Скит ; пер. с англ,
и ред. В. А. Коваленко. - 2-е изд. - 6 Мб. - М.: Вильямс, 2011.
10. Троелсен, Э. C# и платформа .NET / Э. Троелсен ; Э. Троелсен. -
СПб. : Питер, 2006. - 796с. : ил. - (Библиотека программиста). - Перевод
изд.: C# and the platform. NET/ by A. Troelsen.
11. Шилдт, Г. C# 4.0: полное руководство [Электронный ресурс] =
Н. Schildt. C# 4.0: the complete reference / Г. Шилдт ; Г. Шилдт ; пер.
с англ, и ред. И. В. Бернштейна. - 8 Мб. - М.: Вильямс, 2012
230
Книги почтой
Заказ можно сделать на сайте издательства
www.infra-e.ru
№
п/п
Наименование книги
1
Алгоритмы Data Science и их практическая реализация на Python
2
Архитектурно-конфигурируемые SDR-технологии радиомониторинга
и телеметрии
3
Волоконно-оптическая техника. Практическое руководство. Издание 5-е
4
Волоконно-оптические линии связи и их защита от внешних влияний
5
Интернет вещей для начинающих. Визуальное программирование
микроконтроллеров семейства ESP8266
6
Кибероружие и кибербезопасность. О сложных вещах простыми словами
7
Компонентная база инфокоммуникационных и интеллектуальных систем
8
Компьютерные сети
9
Материалы и устройства наноэлектроники. Электроника после Мура
10
Мобильная связь на пути к 6G. Том 1. Издание 3-е
11
Мобильная связь на пути к 6G. Том 2. Издание 3-е
12
Основы микросенсорики
13
Отечественная компонентная база волоконной техники и фотоники
14
Производство гибридных интегральных схем
15
Системы сигнализации мультисервисных сетей
16
Справочник ГГ-терминов
17
Средства специализированных телекоммуникационных шин и сетей систем
управления
18
Теория электрической связи
19
Теория электрической связи через цифровую обработку сигналов с примерами
в MATLAB
20
Техническое и программное обеспечение вычислительных машин и систем
21
Технологические процессы в микро- и наноэлектронике
22
Технологические сети и системы связи
Учебное издание
МАРТЫНЕНКО Татьяна Владимировна
ТУРУПАЛОВ Виктор Владимирович
АНДРИЕВСКАЯ Наталия Климовна
ОСНОВЫ
ВИЗУАЛЬНОГО ПРОГРАММИРОВАНИЯ
В СРЕДЕ VISUAL STUDIO НА БАЗЕ C#
Учебное пособие
Под общейредакцией
кандидата технических наук, профессора В. В. Турупалова
Подписано в печать 25.08.2022
Формат 60*84/16. Бумага офсетная.
Гарнитура «Таймс».
Издательство «Инфра-Инженерия»
160011, г. Вологда, ул. Козленская, д. 63
Тел.: 8 (800) 250-66-01
E-mail: booking@infra-e.ru
http://infra-e.ru
Издательство приглашает
к сотрудничеству авторов
научно-технической литературы