ББК 32.973.2-018.1я7

УДК 004.43(075)

В19


Васильев А.

В19 C#.

Объектно-ориентированное программирование: Учебный курс. — СПб.: Пи-

тер, 2012. — 320 с.: ил.


ISBN 978-5-459-01238-5

Книга представляет собой учебный курс по объектно-ориентированному программированию на

языке C#. Описаны синтаксические конструкции, операторы управления и объектная модель, ис-

пользуемые в C#. В издание включены основные темы для изучения данного языка программиро-

вания, а именно: базовые типы данных и операторы, управляющие инструкции, массивы, классы

и объекты, наследование, индексаторы, свойства, делегаты, обработка исключительных ситуаций, многопоточное программирование, перегрузка операторов, разработка Windows-приложений

и многое другое. Большое внимание уделяется созданию программ с графическим интерфейсом.


ББК 32.973.2-018.1я7


УДК 004.43(075)

Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было фор-

ме без письменного разрешения владельцев авторских прав.

Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как

надежные. Тем не менее, имея в виду возможные человеческие или технические ошибки, издательство не

может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности за

возможные ошибки, связанные с использованием книги.

ISBN 978-5-459-01238-5

© ООО Издательство «Питер», 2012


Оглавление

Вступление. Язык программирования C# .....................................................7

Краткий курс истории языкознания ............................................................................8

Особенности и идеология C# ...................................................................................... 10

Программное обеспечение ............................................................................................ 12

Установка Visual C# Express ........................................................................................ 14

Немного о книге ............................................................................................................... 21

Благодарности ................................................................................................................... 22

От издательства ................................................................................................................ 22

Глава 1. Информация к размышлению: язык C# и даже больше ...................23

Очень простая программа ............................................................................................. 24

Несколько слов об ООП ................................................................................................ 34

Еще одна простая программа ....................................................................................... 36

Консольная программа .................................................................................................. 42

Глава 2. Классы и объекты .......................................................................53

Описание класса ............................................................................................................... 53

Объектные переменные и создание объектов ........................................................ 56

Перегрузка методов ......................................................................................................... 60

Конструкторы и деструкторы ...................................................................................... 64

Наследование и уровни доступа ................................................................................. 72

Объектные переменные и наследование .................................................................. 81

Замещение членов класса и переопределение методов ...................................... 85

Статические члены класса ............................................................................................ 93

6

Оглавление

Глава 3. Основы синтаксиса языка C#.........................................................98

Базовые типы данных и основные операторы ....................................................... 98

Основные управляющие инструкции ..................................................................... 108

Массивы большие и маленькие ................................................................................ 125

Массивы экзотические и не очень ........................................................................... 134

Знакомство с указателями .......................................................................................... 140

Глава 4. Перегрузка операторов ..............................................................143

Операторные методы и перегрузка операторов .................................................. 143

Перегрузка арифметических операторов и операторов

приведения типа ............................................................................................................. 151

Перегрузка операторов отношений ......................................................................... 163

Глава 5. Свойства, индексаторы и прочая экзотика ...................................175

Свойства ............................................................................................................................ 176

Индексаторы .................................................................................................................... 184

Делегаты ............................................................................................................................ 193

Знакомство с событиями ............................................................................................. 199

Элементарная обработка событий ........................................................................... 203

Глава 6. Важные конструкции .................................................................211

Перечисления .................................................................................................................. 211

Знакомство со структурами ....................................................................................... 214

Абстрактные классы ...................................................................................................... 218

Интерфейсы ..................................................................................................................... 227

Интерфейсные переменные ....................................................................................... 237

Глава 7. Методы и классы во всей красе ...................................................242

Механизм передачи аргументов методам .............................................................. 242

Аргументы без значений и переменное количество аргументов ................... 251

Передача типа в качестве параметра ....................................................................... 256

Использование обобщенного типа данных ........................................................... 261

Обработка исключительных ситуаций ................................................................... 265

Многопоточное программирование ........................................................................ 273

Глава 8. Приложение с графическим интерфейсом: учебный проект .........280

Общие сведения о графических элементах .......................................................... 282

Программный код и выполнение программы ...................................................... 284

Наиболее значимые места программного кода .................................................... 300

Вместо заключения. Графический конструктор .........................................305

Создание простого окна с кнопкой .......................................................................... 306

ВСТУПЛЕНИЕ Язык

программирования C#

Наука — это организованное знание.

Г. Спенсер

У прогрессивного человечества, форпостом которого является армия про-

граммистов, есть такие чудесные языки программирования, как C++ и Java.

На первый взгляд может показаться, что этого вполне достаточно. Но не

все так просто.

Какой же язык программирования дополняет тандем из C++ и Java? Это

язык программирования C# (читается « си шарп»).

ПРИМЕЧАНИЕ Такое довольно оригинальное название языка программирования

имеет следующее не менее оригинальное объяснение. Как извест-

но, оператор инкремента ++, который используется в С++, Java и C#, предназначен  для  увеличения  на  единицу  операнда,  который  ис-

пользуется  с  этим  оператором.  Поэтому,  например,  название  С++

можно объяснить как «следующая версия после С». Язык C# — это

«следующая версия после С++». Символ # в данном случае интер-

претируется как два оператора инкремента ++, объединенных, путем

«сдвига»  и  «уплотнения»  четырех  плюсов  (по  два  плюса  в  ряд), в один символ.

Язык программирования C# достаточно молодой. Он создавался в конце

90-х годов прошлого столетия разработчиками из компании Microsoft. Од-

ним из отцов-основателей языка считается Андерс Хейлсберг — тот самый,

8

Вступление. Язык программирования C#

который создал себе имя как идейный архитектор таких чудесных проек-

тов, как Turbo Pascal и Delphi. Идеологически и синтаксически язык C#

близок к С++ и Java. Во всяком случае, если читатель знаком хотя бы с од-

ним из этих языков, он найдет для себя много знакомых пассажей. Все это

не случайно, поскольку язык C# является логическим продолжением язы-

ка C++ (во всяком случае, по мнению разработчиков языка) и в некотором

смысле конкурентом языка Java. Но обо всем по порядку.

Краткий курс истории языкознания

Разница между языками столь велика, что

одно и то же выражение кажется грубым

в одном языке, и возвышенным в другом.

Дж. Драйден

Вначале был язык программирования, и это был язык С. Затем появился

язык С++, который стал расширением языка С до объектно-ориентиро ван-

ной парадигмы. Другими словами, в языке С++ появилась возможность

использовать все ужасные атрибуты объектно-ориентрованного програм-

мирования (сокращенно ООП): классы, объекты, наследование и многое

другое. Поэтому язык С++ во многом стал «законодателем моды» и задал

стиль на годы вперед. Кроме того, принципиальная особенность языка С++

состоит в том, что это язык «переходной» — в С++ можно писать как про-

граммы в рамках парадигмы ООП, так и обычные программы, не имеющие

никакого отношения к ООП.

ПРИМЕЧАНИЕ Другими словами, при создании программного кода в С++ классы

и объекты можно использовать, а можно не использовать. В языках

Java и C# это непозволительная роскошь.

Язык программирования Java появился после языка С++. Зародился и раз-

рабатывался язык Java в недрах компании Sun Microsystems (сейчас она

поглощена корпорацией Oracle). В отличие от С++, язык Java полностью

объектно-ориентированный. Данное жизнеутверждающее обстоятельство

имеет самые неприятные последствия: для написания самой маленькой

программы в Java приходится создавать класс. В принципе, с технической

точки зрения ничего сложного в этом нет, но вот психологический барьер

есть, и особенно он ощутим для новичков. Вместе с тем язык Java завоевал

свое место под солнцем благодаря другим своим уникальным свойствам.

В первую очередь, это относительная универсальность программных кодов

Краткий курс истории языкознания           9

в плане непритязательности к типу операционной системы и параметрам

аппаратного обеспечения. Язык Java создавался под лозунгом «написано

единожды, работает везде». Результат достигается за счет компиляции

программного кода в промежуточный байт-код, который выполняется спе-

циальной программой — виртуальной Java-машиной.

ПРИМЕЧАНИЕ В С++ программа компилируется в исполнительный код. В Java после

компиляции получается промежуточный код. Поэтому в общем случае

программы, написанные на С++, работают быстрее, чем аналогичные

программы,  написанные  на  Java.  Вместе  с  тем  программные  коды

Java более универсальны. Во времена всеобщего развития интернет-

технологий вопрос универсальности становится определяющим. Это

обстоятельство во многом и обусловило популярность и бурное раз-

витие Java. Кроме того, технология Java является хорошей платфор-

мой для программирования бытовых устройств, а основные средства

разработки для Java распространяются бесплатно.

Что касается синтаксиса Java, то он во многом напоминает синтаксис язы-

ка С++. Вообще, очень многие моменты в языках схожи. Фактически, раз-

работчики Java попытались выявить, учесть и устранить все неприятные

моменты, обнаруженные в С++. Получилось неплохо, но не идеально. Тем

не менее язык Java прошел проверку временем. И когда данное обстоятель-

ство стало более-менее очевидным, на сцену вышла корпорация Microsoft с языком программирования C#.

Нередко о языке C# отзываются как об «ответе» со стороны компании

Microsoft в сторону компании Sun Microsystems. Вместе с тем язык C#

нельзя (да и неправильно) рассматривать как банальную альтернативу

языку Java. У Microsoft в отношении языка C# далеко идущие планы.

Язык C# ориентирован в первую очередь на операционную систему

Windows.

Почему-то это нисколько не удивляет. И хотя периодически выпол-

няются  попытки  расширить  область  применимости  языка  C#  и  со-

путствующих технологий на другие операционные системы, питать

иллюзии по этому поводу все же не стоит.

Другими словами, если мы собираемся программировать на C#, то мы со-

бираемся программировать для Windows. Связано это не столько с язы-

ком C#, сколько с платформой .NET (рекомендуется читать « дот нет»), под которую и разрабатывался язык — язык C# анонсирован как базовый

язык для реализации в рамках технологии .NET. Это еще одно детище

10

Вступление. Язык программирования C#

Microsoft, на самом деле тесно связанное с языком C#. Bот c этой парой

нам надо бы разобраться.

Особенности и идеология C#

Идеи — редкая дичь в лесу слов.

В. Гюго

Исполнительная среда (или платформа) .NET Framework предложена и под-

держивается компанией Microsoft как средство для выполнения приложе-

ний, компоненты (составные части) которых написаны на разных языках

программирования. Язык программирования C# тесно связан с этой тех-

нологией, поскольку многие важные для C# библиотеки являются состав-

ной частью среды .NET Framework и, что более важно, откомпилирован-

ные C#-программы выполняются под управлением этой среды.

ПРИМЕЧАНИЕ На обычном языке это означает следующее: если на компьютере не

установлена платформа .NET Framework, про программирование в C#

можно забыть.

Совершенно очевидно, что для совместной работы или совместного ис-

пользования компонентов, написанных на разных языках, необходима

«военная хитрость». Военная хитрость состоит в том, что при компиляции

программного кода получается промежуточный псевдокод.

ПРИМЕЧАНИЕ Промежуточный псевдокод называется общим промежуточным язы-

ком, или CIL — сокращение от Common Intermediate Language.

Псевдокод выполняется под управлением специальной системы, которая

является составной частью платформы .NET Framework и называется

CLR — сокращение от Common Language Runtime. Система CLR, в свою

очередь, для выполнения промежуточного псевдокода вызывает специ-

альный встроенный в среду компилятор. Компилятор переводит псевдо-

код в исполнительный код. Делается это непосредственно перед выпол-

нением программы, что существенно оптимизирует время выполнения

кода.

Особенности и идеология C#           11

ПРИМЕЧАНИЕ Ситуация несколько напоминает процесс компиляции и выполнения

Java-кодов. При компиляции Java-программ также получается не ис-

полнительный код, а промежуточный байт-код, который выполняет-

ся виртуальной Java-машиной (JVM как сокращение от Java Virtual Machine) — аналогом системы CLR. Однако за внешней схожестью здесь

имеются существенные принципиальные различия. Обратим внимание

читателя на два обстоятельства. Во-первых, необходимость компили-

рования программ в промежуточный код в Java обусловлена желанием

универсализации программных кодов, в то время как в .NET Framework (и C# как базового языка платформы) «появление» промежуточного

кода имеет целью «свести к общему знаменателю» программные моду-

ли, написанные на разных языках. Как следствие промежуточный код

CIL не привязан к какому-то конкретному языку программирования

или определенному типу процессора. Во-вторых, наличие встроенного

эффективного компилятора в .NET Framework практически нивелирует

неэффективность времени исполнения, связанную с использованием

промежуточного кода (вместо исполнительного).

Все вышесказанное характеризует общее направление развития языка C#.

Для нас из всего вышеизложенного важным является то, что мы неявно

в этой книге будем предполагать, что составляемые программные коды

предназначены для исполнения в операционной системе Windows.

Для читателей, знакомых с языками Java и (или) C++, несколько слов

хочется сказать и о том, что отличает/объединяет языки C++ и Java, с

одной стороны, и язык C# с другой. Общую генелогию этих языков мы

кратко упоминали. У всех трех языков достаточно схожий синтаксис, равно как и большинство управляющих инструкций (таких, напри-

мер, как операторы цикла или условные операторы). Язык C#, так же

как и Java, полностью объектно-ориентированный. Самая маленькая

и безобидная программа, написанная на C#, содержит хотя бы один

класс. У языков C# и Java достаточно схожие объектные модели —

в плане реализации классов и объектов. Вообще, в языке C# собрано

все лучшее, что есть в C++ и Java, и по большей части устранены недо-

статки этих языков (хотя, конечно, до полной виктории очень далеко).

Например, в C#, так же как в C++, используется концепция пространства

имен. В C# можно использовать указатели и переопределять опера-

торы — правда, не на таком уровне, как в C++, но в Java этого вообще

нет. В C# есть делегаты, которые играют роль, аналогичную указателям

на функции в C++. Вместе с тем в C# объекты передаются по ссылке

(как в Java), используются интерфейсы (как в Java), используется

аналогичная Java система «сборки мусора» (автоматическое удаление

неиспользуемых объектов) и система обработки исключительных си-

туаций. Есть в C# и целый набор достаточно оригинальных и полезных

новшеств, с которыми мы, безусловно, познакомимся.

12

Вступление. Язык программирования C#

Программное обеспечение

Это дело очень интересное. И простое.

Из к/ф «Приключения Шерлока Холмса

и доктора Ватсона. Знакомство»

С «идеологией» и «концепцией» мы более-менее разобрались. Все это, ко-

нечно, хорошо, но пора перейти к вещам более практичным. Ведь главный

вопрос остался неразрешенным: что нужно сделать, чтобы создать про-

грамму на C#? Или, более конкретно, какое программное обеспечение для

этого нужно? Для ответа на этот вопрос напомним, из чего, собственно, состоит процесс создания программы. Состоит он, в самых общих чертах, из следующих этапов.


 Набор (составление) программного кода (с учетом синтаксиса языка

C#).


 Компиляция программного кода.


 Выполнение откомпилированного (исполнительного) кода.

Первый этап пока пропустим и будем исходить из того, что программный

код у нас уже есть (ну вот как-то он появился). Нам его необходимо отком-

пилировать. Для этого нужна специальная программа, которая называется

компилятором. Компилятор для языка C# поставляется как составная часть

платформы .NET Framework. Соответствующий файл называется csc.exe.

Таким образом, для компиляции программы необходимо установить плат-

форму .NET Framework. Установочные файлы можно свободно (то есть

бесплатно) загрузить с сайта www.microsoft.com компании Microsoft. Ду-

мается, особых проблем эта процедура у читателя не вызовет.

Если читатель использует операционную систему Windows и другие

популярные продукты компании Microsoft, то, скорее всего, платфор-

ма .NET Framework уже установлена. Во всяком случае, имеет смысл

проверить систему на наличие файла csc.exe.

Например, если программный код, предназначенный для компиляции, записан в файл MyProgram.cs (у файлов с C#-программным кодом расши-

рение .cs), то для компиляции кода в командную строку вводим команду

csc.exe MyProgram.cs. Если в программном коде нет ошибок и компиляции

выполнена успешно, будет создан файл с таким же именем, но расширени-

ем .exe — в нашем случае это файл MyProgram.exe. Это исполнительный

файл. Чтобы увидеть, как работает программа, следует запустить этот файл

на выполнение.

Программное обеспечение           13

Хотя «на выходе» мы получаем исполнительный файл с расширением

.exe, просто перенести (скопировать) этот файл на другой компьютер

для выполнения на нем программы в общем случае не получится.

Файл хотя и исполнительный, но выполняется под управлением CLR-

системы.  Такой  код  называют  контролируемым.  На  практике  это

означает,  что  для  выполнения  такого  exe-файла  на  компьютере

должна быть установлена платформа .NET Framework.

Что касается набора программного кода, делать это можно хоть в тексто-

вом редакторе — главное, чтобы программа, в которой набирается код, не

добавляла свои специфические инструкции в файл (который должен быть

сохранен с расширением .cs). Само собой разумеется, что описанный выше

способ программирования в C# совершенно неприемлем. Мы им пользо-

ваться не будем.

Программировать (в том числе и на C#) лучше и проще всего с помо-

щью интегрированной среды разработки ( IDE от Integrated Development Environment). Интегрированная среда разработки — это специальная про-

грамма, которая обычно включает в себя редактор программных кодов и на-

бор всевозможных утилит. Нередко в состав среды входят и необходимые

компиляторы, интерпретаторы и надстройки. Все зависит от того, на каком

языке мы собираемся программировать. Нас в данном конкретном случае

интересует C#, поэтому и интегрированная среда разработки нам нужна

для программирования на C#. Поскольку язык C# разработан и поддер-

живается компанией Microsoft, интегрированную среду для нашего обще-

го дела тоже разумно искать в линейке программных продуктов Microsoft.

Здесь можно выделить Visual Studio, но это продукт коммерческий и не-

дешевый. Есть более простая и бесплатная версия интегрированной среды

разработки из серии Express Edition. Ее можно свободно (бесплатно) загру-

зить с сайта компании Microsoft. В книге мы будем использовать версию

Visual C# 2010 Express. Процесс установки этой интегрированной среды

кратко описан в следующем разделе.

ПРИМЕЧАНИЕ В книге мы особо заострять внимание на среде разработки не будем.

Исключение составляют случаи, когда принципиально важное место

в понимании того или иного примера занимают операции, выполняе-

мые пользователем/программистом в окне среды разработки. Объяс-

нения даются для среды Visual C# 2010 Express. Не должны возникнуть

проблемы и в случае, если читатель использует другую IDE из линейки

Express Edition или Visual Studio. Рассматриваемые в основной части

книги примеры (в плане программного кода) достаточно универсаль-

ны. Тем не менее следует понимать, что программный код оптимизи-

рован именно для работы со средой Visual C# 2010 Express.

14

Вступление. Язык программирования C#

Какие преимущества дает использование IDE (в данном случае Visual C#

2010 Express)? Как минимум, это исключительно удобный и функцио-

нальный редактор программных кодов. Редактор кодов — вещь незамени-

мая, особенно для новичков в программировании. Например, при наборе

кодов автоматически проверяется синтаксис и выводится контекстная

подсказка. Последнее особенно актуально при работе с классами и объек-

тами, поскольку позволяет быстро и эффективно просматривать полный

список доступных полей и методов. Если добавить сюда утилиты для от-

ладки и отслеживания программного кода, возможность компилировать

и запускать на выполнение программы одним щелчком мыши, не выходя

из окна среды разработки, удобную справочную систему и графический

редактор для создания оконных форм (используется при написании про-

грамм с графическим интерфейсом), то каждому станет очевидно, что IDE

лучше иметь под рукой. На этом и остановимся.

Установка Visual C# Express

— Ладно, все. Надо что-то делать.

Давай-ка, может быть, сами изобретем.

— Витя, не надо! Я прошу тебя.

Не дразни начальство!

Из к/ф «Чародеи»

Процесс установки приложения Visual C# 2010 Express достаточно прост

и состоит из нескольких этапов. На первом этапе следует загрузить устано-

вочные файлы. Для этого на сайте www.microsoft.com компании Microsoft находим страницу загрузки файлов Visual C# 2010 Express. На рис. В.1 за-

печатлен момент, когда мы щелкаем на гиперссылке, желая закачать уста-

новочные файлы для Visual C# 2010 Express.

Загружаем установочные файлы (точнее, файл). Этот файл запускаем на

выполнение. В результате появляется окно, похожее на то, что представ-

лено на рис. В.2.

Для начала установки необходимо согласиться с условиями лицензии

(рис. В.3).

Не исключено, что нас попросят определиться с некоторыми дополнитель-

ными продуктами, которые любезно предоставляет корпорация Microsoft.

Нечто подобное проиллюстрировано рис. В.4.

Установка Visual C# Express           15

Рис. В.1.  Загрузка установочных файлов Visual C# Express Рис. В.2.  Начинаем установку

16

Вступление. Язык программирования C#

Рис. В.3.  Соглашаемся на условия Microsoft

Рис. В.4.  Дополнительные продукты для установки

Перед тем, как все начнет устанавливаться, необходимо указать место (ко-

нечную папку) установки. На рис. В.5 показано соответствующее диалого-

вое окно.

Установка Visual C# Express           17

В этом же окне представлено «полное меню установки» — перечислены те

компоненты, которые будут установлены. Многое зависит от того, что ра-

нее уже было установлено пользователем, но обычно список немаленький.

Затем начинается непосредственно процесс установки (рис. В.6).

Рис. В.5.  Выбор папки для установки программного продукта

Рис. В.6.  Идет установка

18

Вступление. Язык программирования C#

В принципе процесс автономный, но расслабляться не стоит, поскольку

наступит момент, когда придется принимать решение: перезагружать или

не перезагружать (рис. В.7).

Рис. В.7.  В какой-то момент предстоит принять непростое решение

Путь смелых и решительных — перезагружать. После этого процесс уста-

новки продолжится как ни в чем не бывало (рис. В.8).

Наше долготерпение будет вознаграждено диалоговым окном с сообщени-

ем о том, что процесс установки завершен (рис. В.9).

В принципе, на некоторое время наши заботы закончились. Почему на не-

которое время? Потому что продукт еще нужно зарегистрировать. Реги-

страция бесплатная, но без регистрации надолго программного продукта

не хватит — он очень быстро придет в негодность.

Для начала процесса регистрации запускаем приложение Visual C# Express и в окне приложения в меню Справка выбираем команду Зарегистрировать про-

дукт, как показано на рис. В.10.

Откроется диалоговое окно с полем для ввода ключа регистрации и кноп-

кой Получить регистрационный ключ через Интернет (рис. В.11).

ПРИМЕЧАНИЕ Что делать, если доступа в Интернет нет, Microsoft не сообщает.

Установка Visual C# Express           19

Многие в этом месте вздохнут с облегчением – казалось бы, достаточно

щелкнуть на кнопке и получить ключ. Пожелаем оптимистам успеха!

Рис. В.8.  Процесс установки продолжается

Рис. В.9.  Установка завершена

20

Всьупление. Язык программирования C#

Рис. В.10.  Рано или поздно придется зарегистрировать продукт

Рис. В.11.  Получение регистрационного ключа от Microsoft

Немного о книге           21

Немного о книге

— Товарищ Тройкина, мы вас целых пять

минут уже здесь ждем. Вы же знаете, у нас

срочная работа.

— Извините. Читала – увлеклась. Такая

книжка интересная попалась!

Из к/ф «Безумный день инженера

Баркасова»

Перед тем как перейти непосредственно к основной части книги и погру-

зиться в мир программных кодов, все же имеет смысл сказать/написать

несколько слов о самой книге. О том, что книга о языке C# и методах про-

граммирования на этом языке, читатель уже догадался.

Материал книги разбит на главы, и каждая глава посвящена какой-то от-

дельной теме. При этом использовался принцип, что даже самый захуда-

лый пример намного лучше самой изысканной теории. Поэтому знаком-

ство читателя с языком программирования C# в первой главе начинается

с простенького примера. Затем идет объяснение того, почему пример рабо-

тает, и работает именно так, а не как-то иначе. Вообще, материал излагает-

ся последовательно в том смысле, что для понимания происходящего, как

правило, не нужно лихорадочно листать следующие темы.

ПРИМЕЧАНИЕ Но иногда это все же делать придется.

Конечно же, в книгу вошло далеко не все, что касается, так или иначе, язы-

ка программирования C#. Вместе с тем основные темы здесь собраны. Так

что достаточно объективное и во многом полное представление о возмож-

ностях языка C# читатель составить сможет.

Здесь особо хочется подчеркнуть, что книга о языке C#, а не о среде

разработки Visual C# Express. Поэтому обсуждать мы будем методы

программирования на языке C#, а не методы программирования на

языке C# в среде Visual C# Express. Хотя предполагается, что именно

эту среду и будем использовать для набора кода, компиляции и вы-

полнения программ.

Обычно изучение языка начинают с консольных программ. Это в принци-

пе разумно. Но язык C# создавался не для того, чтобы писать консольные

22

Вступление. Язык программирования C#

программы. Поэтому, где только возможно, мы будем использовать графи-

ческий интерфейс.

Все отзывы о книге и пожелания можно зафиксировать в письме и отпра-

вить его по адресу alex@vasilev.kiev.ua или по адресам, которые указаны

на странице автора www.vasilev.kiev.ua.

На этом мы заканчиваем разговоры и переходим к непосредственному

делу — изучению языка программирования C#.

Благодарности

Благодарность большинства людей

обычно скрывает ожидание еще больших

благодеяний.

Ф. Ларошфуко

Автору приятно выразить искреннюю признательность издательству «Пи-

тер» и лично Андрею Юрченко за открытость, креативность и профессио-

нальную работу. Хочется также от всего сердца поблагодарить редактора

книги Ольгу Некруткину, благодаря ее кропотливой работе книга стала

значительно лучше.

От издательства

Ваши замечания, предложения, вопросы отправляйте по адресу электрон-

ной почты comp@piter.com (издательство «Питер», компьютерная редак-

ция).

Мы будем рады узнать ваше мнение!

Все исходные тексты, приведенные в книге, вы можете найти по адресу

http://www.piter.com.

На веб-сайте издательства http://www.piter.com вы найдете подробную ин-

формацию о наших книгах.

Информация

к размышлению:

язык C# и даже

больше

Только я тебя прошу – говори спокойно,

без ораторского нажима.

Из к/ф «Безумный день инженера

Баркасова»

В этой главе мы наконец перейдем от слов к делу и начнем программиро-

вать. Действуя смело и решительно, мы сразу же


 создадим программу с графическим интерфейсом;


 определимся с тем, как ее откомпилировать и запустить на выполне-

ние;


 оценим результат;


 выясним причины такого успеха.

В процессе мы пройдем очень краткий курс работы со средой разработки

Visual C# 2010 Express и обсудим особенности объектно-ориентированного

программирования. Вооружившись этими знаниями, мы рассмотрим еще

несколько примеров и только после этого приступим к изучению азов язы-

ка C#. Таков наш план на эту главу.

24

Глава 1. Информация к размышлению: язык C# и даже больше

Очень простая программа

Простота — это то, что труднее всего

на свете. Это крайний предел опытности

и последнее усилие гения.

Жорж Санд

Наступило время воплотить в жизнь идею об очень маленькой и очень

простой программе с графическим интерфейсом. Идея представлена в лис-

тинге 1.1.

Листинг 1.1. Очень простая программа

using System.Windows.Forms;

// Описание класса:

class HelloWindow{

// Главный метод программы:

static void Main(){

// Отображение окна:

MessageBox.Show("Всем огромный привет!");

}

}

Сразу откроем завесу тайны: в результате выполнения этой программы

открывается диалоговое окно с сообщением Всем огромный привет!. Этот

же программный код в окне редактора среды разработки Visual C# Express представлен на рис. 1.1.

Что нужно сделать, чтобы код оказался в этом окне, мы опишем чуть поз-

же. Сейчас же для нас важно обратить внимание на пиктограмму с зеле-

ной маленькой стрелкой на панели инструментов окна редактора кодов.

Щелчок на этой пиктограмме (или, как альтернатива, нажатие клавиши F5) приводит к автоматической отладке/компиляции программы и, в случае

успеха, ее запуску на выполнение. В результате появится диалоговое окно, представленное на рис. 1.2.

В области окна содержится анонсированный ранее текст. Также у окна есть

кнопка OK, щелчок на которой приводит к закрытию окна.

Чтобы воочию увидеть всю эту красоту, необходимо выполнить следующие

нехитрые действия. Итак, запускаем приложение Visual C# 2010 Express.

В результате открывается окно, представленное на рис. 1.3.

Очень простая программа           25

Рис. 1.1.  Программный код в окне редактора среды Visual C# Express Рис. 1.2.  Такое диалоговое окно появляется

в результате выполнения программы

Рис. 1.3.  Окно приложения Visual C# 2010 Express

26

Глава 1. Информация к размышлению: язык C# и даже больше

ПРИМЕЧАНИЕ При первом запуске приложения Visual C# 2010 Express появится

внутреннее окно приветствия. Его можно закрыть.

В меню Файл приложения выбираем команду Создать  проект (комбинация

клавиш Ctrl+Shift+N). Откроется диалоговое окно Создать  проект, в котором

следует выбрать тип создаваемого проекта (рис. 1.4).

Рис. 1.4.  Выбираем тип создаваемого проекта

Откровенно говоря, здесь можно идти разным путями. Мы пойдем наи-

более прямым и достаточно простым — будем создавать приложение

для Windows (то есть не консольное приложение). В этом случае выби-

раем в списке в центральной части окна Создать  проект позицию Приложе-

ние Windows Forms, а в поле Имя (в нижней части окна) указываем имя про-

екта — в данном случае FirstProgram. Окно среды разработки после этого

примет вид, как на рис. 1.5.

Что мы видим? Видим мы внутреннее окно-вкладку с формой (в левой ча-

сти рабочего окна среды разработки) и внутреннее окно Обозреватель решений

(соответственно, в правой части рабочего окна среды разработки). В прин-

ципе форма — неотъемлемая часть приложения с графическим интерфей-

сом. Но в данном конкретном случае она нам не понадобится — у нас уже

есть планы насчет отображения стандартного диалогового окна. Поэтому

форму из проекта удаляем.

Очень простая программа           27

Рис. 1.5.  Удаляем из проекта форму

Если у приложения есть графический интерфейс, то, очевидно, при

запуске  приложения  хоть  какое-то  окно,  да  отображается.  Чтобы

окно отобразилось, его надо как-то и где-то описать. В принципе, возможны такие варианты:

воспользоваться стандартным окном;

создать окно непосредственно в программном коде.

Мы в нашей первой программе идем первым путем — образно вы-

ражаясь, используем стандартную библиотеку для отображения стан-

дартного окна. Преимущество очевидное — минимальный объем про-

граммного кода, поскольку почти весь необходимый для отображения

окна код для нас уже написали хорошие люди. Минус тоже очевид-

ный — окно будет именно таким, как его описали хорошие люди. Не

факт, что нам тоже нужно такое окно. Здесь мы скромно соглашаемся

на предлагаемый вариант. Но впоследствии наши аппетиты вырастут, и мы будем создавать такие окна, какие нужны нам, а не просто до-

вольствоваться существующим (или, по крайней мере, укажем пути

создания окон с требующимися характеристиками). Создавать окна

будем с помощью самых незатейливых команд. Вместе с тем, если

мы работаем со средой Visual C# Express (а мы с ней действительно

работаем), у нас есть еще одна возможность:

воспользоваться графическим конструктором для создания одной

или нескольких форм (то есть окон, отображаемых при выполне-

нии программы) и написания кода для обработки событий (этот

код определяет реакцию окна на действия пользователя).

28

Глава 1. Информация к размышлению: язык C# и даже больше

Это достаточно удобный способ создания приложений с графическим

интерфейсом, но относится он не столько к возможностям языка C#, сколько к особенностям среды разработки Visual C# Express. К тому

же такой способ создания приложений считается не очень профес-

сиональным. Поэтому заострять внимание на нем не будем. Вместе

с тем в Заключении представлено небольшое руководство по созданию

приложений  с  графическим  интерфейсом  путем  конструирования

форм вручную.

При  создании  приложения  для  Windows  в  среде  Visual  C#  Express автоматически  создается  пустая  форма,  которую  мы  и  наблюдали

в рабочем окне среды на рис. 1.5. Поскольку использовать эту форму

мы не собираемся, мы просто удаляем ее из проекта.

Для удаления формы в окне Обозреватель решений выделяем пункт Form1.cs, соответствующий форме, и после этого нажимаем клавишу Del. Можно

также воспользоваться командой Удалить контекстного меню или командой

Удалить из списка команд меню Правка. После удаления формы выполняем

двойной щелчок на пункте Program.cs в окне Обозреватель решений, в резуль-

тате чего слева во внутреннем окне вкладки будет отображен программный

код (рис. 1.6).

Рис. 1.6.  Переходим к редактированию программного кода

Это «шаблонный» код — он автоматически подставляется при создании

новой программы. Мы его редактируем: удаляем предложенный «шаблон-

ный» код и вводим тот, что представлен в листинге 1.1.

Очень простая программа           29

ПРИМЕЧАНИЕ Выше мы использовали термин проект. При работе со средой разра-

ботки обычно создаются проекты — помимо непосредственно файла

с кодом программы автоматически создаются и некоторые вспомо-

гательные файлы. Но нас интересует исключительно программный

код. По умолчанию код программы записывается в файл Program.cs.

При желании название этого файла можно изменить прямо в окне

Обозреватель решений.

После ввода программного кода окно среды должно иметь вид, как на

рис. 1.1. В принципе, на этом процесс создания программы завершен.

Осталось только сохранить проект: выбираем команду Сохранить все в меню

Файл или щелкаем на соответствующей кнопке на панели инструментов

(рис. 1.7).

Рис. 1.7.  Сохраняем проект

Откроется диалоговое окно Сохранить проект, в котором необходимо указать

имя для проекта (поле Имя) и в поле Расположение задать место, в котором

будет сохранен проект (рис. 1.8).

Рис. 1.8.  Диалоговое окно сохранения проекта

ПРИМЕЧАНИЕ Если установлен флажок Создать каталог для решения, файлы проекта

будут сохраняться в отдельной папке. Значение в поле Имя решения

автоматически устанавливается таким же, как и имя проекта. Однако

значение поля Имя решения можно изменить. Значение в этом поле

определяет название папки, в которой будут храниться файлы про-

30

Глава 1. Информация к размышлению: язык C# и даже больше

екта. Название в поле Имя определяет, кроме прочего, имя испол-

нительного файла. Это файл с расширением .exe. Для выполнения

программы следует запустить на выполнение этот файл. При работе

со средой разработки все эти действия выполняются автоматически.

По умолчанию exe-файл находится в подкаталоге bin\Debug папки

с названием Имя решения\Имя.

С формальностями мы закончили. Теперь пора перейти к анализу про-

граммного кода (вспоминаем о листинге 1.1). Один важный момент от-

метим сразу: все, что начинается с двойной косой черты, является ком-

ментарием и компилятором игнорируется. Другими словами, следующие

инструкции предназначены исключительно для homo sapience, которые бу-

дут просматривать программный код:

// Описание класса:

// Главный метод программы:

// Отображение окна:

Как только компилятор в программном коде встречает две косые черты, он

игнорирует все, что находится справа от них (до конца строки).

ПРИМЕЧАНИЕ Это так называемые однострочные комментарии. Если в программный

код необходимо добавить комментарий, который занимает несколько

строк, обычно используют инструкции /* и */. Все, что находится

между этими инструкциями, является комментарием.

Если убрать комментарии, то непосредственно программный код состоит

из таких инструкций:

using System.Windows.Forms;

class HelloWindow{

static void Main(){

MessageBox.Show("Всем огромный привет!");

}

}

Командой using System.Windows.Forms подключается пространство имен, а все остальное — это описание класса HelloWindow. И с этого места, как

говорится, поподробнее.

Мы уже знаем, что C# — полностью объектно-ориентированный язык, то есть когда мы составляем даже самую маленькую программу, приходит-

ся описывать класс. Что же такое класс? Вопрос простой и одновремен-

но сложный. Мы прибегнем к аналогии. Допустим, нужно построить дом.

Дом строят из чего-то, то есть из строительных материалов. Рассмотрим

Очень простая программа           31

два способа постройки дома. Вариант первый: у нас есть кирпичи, оконные

рамы и дверные блоки. В этом случае мы из кирпичей выкладываем стены, вставляя дверные блоки и оконные рамы. Каковы преимущества данного

подхода? Выложить можно здание практически любой формы с любой

комбинацией и размещением дверей и окон. Каковы недостатки? Он, по-

жалуй, один: если здание очень большое, придется строить долго. К тому

же, если работают несколько бригад строителей, всяких нестыковок и бра-

ка будет более чем достаточно.

Вариант второй. Заказываем на заводе готовые панельные блоки: блок

с окном, блок с дверью, блок с дверью и двумя окнами, и т. д. Складываем

дом из блоков. Какие преимущества? Быстро и просто. Какие недостатки?

Далеко не все можно построить. Если, например, блоки цилиндрической

формы не заказали, то башню уже не построишь.

Постройка дома — это и есть написание программы. Кирпичи играют

роль данных, а двери и окна — это функции (процедуры), которые вы-

полняют некоторые действия. Первый способ построения дома соответ-

ствует классическому процедурному программированию, когда данные

и функции (процедуры) существуют независимо друг от друга и объе-

диняются вместе по потребности, по воле программиста. Этот подход

достаточно эффективен при написании не очень больших программ.

Если же программы большие, то в принципе несложно запутаться среди

огромного набора данных и списка функций. Поэтому при написании

больших и сложных программ прибегают к объектно-ориентированному

программированию — то есть строят дом из блоков. Такой отдельный

блок в ООП называется объектом. В объекте спаяны воедино и данные, и функции — точно так же, как в строительном блоке объединены в одно

целое панели, оконные рамы и дверные проемы. Объект создается по об-

разцу. Этим образцом является класс. Аналог класса — это чертеж, по

которому на заводе изготовляется блок. Таким образом, класс задает

шаблон, по которому создаются объекты. Наличие класса не означает

наличие объекта, точно так же, как наличие чертежа не означает, что соз-

дан строительный блок. При этом создать объект без класса нельзя (во

всяком случае, в C#). На основании одного класса можно создать много

объектов, а можно не создать ни одного. Это именно наш случай — в про-

грамме мы описали класс, но объект на основании этого класса создавать

не будем.

В известном смысле класс напоминает описание типа данных, с той лишь

принципиальной разницей, что кроме непосредственно данных в класс

включаются и функции (как правило, предназначенные для обработки

этих данных).

32

Глава 1. Информация к размышлению: язык C# и даже больше

ПРИМЕЧАНИЕ В ООП принято называть данные, относящиеся к классу, полями клас-

са, а функции, относящиеся к классу, — методами класса. Поля класса

и методы класса называются членами класса. Помимо полей и мето-

дов, классы в C# могут содержать свойства, индексаторы, события.

Все это тоже члены класса, и до них черед еще дойдет.

Но вернемся к нашей программе и разберем код класса HelloWindow. Опи-

сание класса начинается с ключевого слова class. После этого ключевого

слова указывается имя класса. Непосредственно код класса указывается

в блоке из фигурных скобок: открывающей { и закрывающей }.

ПРИМЕЧАНИЕ Эта пара фигурных скобок очень часто используется в C# для вы-

деления программных кодов. Место размещения фигурных скобок

крайне демократично – их можно располагать где угодно, лишь бы

последовательность скобок и команд была правильной.

Как отмечалось выше, класс может содержать данные и методы для их об-

работки. Класс HelloWindow состоит всего из одного метода, который на-

зывается Main().

ПРИМЕЧАНИЕ В книге мы будем указывать имена методов с пустыми круглыми

скобками. Эта хорошая традиция позволяет легко отличать названия

методов от названий переменных. Кроме того, она имеет достаточно

глубокий смысл, который станет понятен после того, как мы позна-

комимся с делегатами.

Метод Main() особенный. Это главный метод программы. Выполнение

программы означает выполнение метода Main(). Другими словами, когда

мы запускаем программу на выполнение, то на самом деле идет инструк-

ция выполнить программный код метода Main().

ПРИМЕЧАНИЕ Программа в C# может содержать (и обычно содержит) описание

нескольких классов. Но всегда есть один класс (который мы иногда

будем называть главным классом программы), в котором есть метод

Main(). Этот метод будет выполнен при выполнении программы.

Перед именем метода Main() указаны атрибуты static и void. Атрибут void означает, что метод не возвращает результат. Атрибут static означает, что

метод статический. О статических методах речь пойдет далее. Важным

Очень простая программа           33

следствием статичности метода является то обстоятельство, что для вызова

метода нет необходимости создавать объект класса, в котором описан метод.

Поэтому-то мы и описываем класс с методом Main(), но не создаем объект

класса. Тело метода (его программный код) заключается в фигурные скобки.

Код метода Main() состоит всего из одной команды MessageBox.Show("Всем

огромный привет!"). Команда заканчивается точкой с запятой — так закан-

чиваются все команды в C#. Как несложно догадаться, именно благодаря

этой команде на экране появляется диалоговое окно. Формально команда

означает следующее: из класса MessageBox вызывается статический метод

Show() с аргументом "Всем огромный привет!". Метод Show() описан в би-

блиотечном классе MessageBox. Согласно используемому в C# и стандарт-

ному для ООП точечному синтаксису при вызове метода указывается так-

же имя объекта (для нестатического метода) или класса (для статического

метода). Имя объекта/класса и имя метода разделяются точкой. Действие

метода Show() состоит в том, что он выводит на экран окно с текстом, ко-

торый указан аргументом метода. Для того чтобы компилятор смог узнать

класс MessageBox, в самом начале программного кода мы подключили про-

странство имен System.Windows.Forms.

ПРИМЕЧАНИЕ Концепция использования пространств имен в C# позволяет струк-

турировать и упорядочить все полезные классы, которые написаны

специально для того, чтобы наша жизнь стала проще. Все классы, которые идут в комплекте поставки с исполнительной системой C#

разбиты на группы, или пространства имен. Когда мы подключаем то

или иное пространство, мы фактически указываем компилятору, где

ему следует искать те классы, на которые мы ссылаемся.

Для подключения пространства имен используют инструкцию using, после  которой  указывается  имя  пространства.  Одно  пространство

может  содержаться  внутри  другого.  В  этом  случае  иерархия  про-

странств  отображается  с  помощью  точечного  синтаксиса  —  как, например, в названии System.Windows.Forms. Обычно в программе

подключается сразу несколько пространств имен.

Помимо рабочего программного кода, из этого раздела мы узнали одну

принципиальную вещь. На ближайшее время все программные коды, ко-

торые мы будем составлять, соответствуют следующему шаблону: using простарнство_имен;

class имя_класса{

static void Main(){

// программный код

}

}

34

Глава 1. Информация к размышлению: язык C# и даже больше

Собственно, все, что нам нужно сделать для составления кода програм-

мы, — это указать имя класса и непосредственно код программы — код

метода Main(). Ну, конечно, еще подключить необходимые простран-

ства имен.

ПРИМЕЧАНИЕ Хотя главный метод программы должен называться Main(), его атри-

буты могут незначительно варьироваться. Например, метод может

возвращать целочисленный результат или принимать аргументы (па-

раметры командной строки).

Несколько слов об ООП

— Ученый совет должен быть в полном составе!

— Кота ученого приглашать будем?

Из к/ф «Чародеи»

Чтобы прочувствовать всю прелесть языка C#, необходимо иметь хотя бы

общее представление об основных принципах ООП, поскольку именно

принципы ООП реализуются в C# по полной программе. И здесь сразу

необходимо отметить, что ООП, строго говоря, появилось не от хорошей

жизни. Главная причина перехода от парадигмы процедурного программи-

рования к концепции ООП произошла, как это ни странно, для того, чтобы

программистам легче и проще было создавать и читать программные коды.

Обычно новшества появляются в ответ на некоторую проблему. Возникает

вопрос: ответом на какую проблему является появление ООП? Проблема

банальная — в какой-то момент объем программных кодов настолько уве-

личился, что держать все под контролем стало практически нереальным.

Что такое программа? Это, по сути, набор инструкций о том, какие дан-

ные и какими методами обрабатывать. Если и данных, и функций для их

обработки много, несложно во всей этой кухне запутаться. Главная идея

ООП как раз и состоит в том, чтобы объединить данные и функции для их

обработки на одном из базовых уровней — на уровне тех «строительных

блоков», из которых создается программа. Эта идея (идея объединения

в одно целое данных и программного кода для их обработки) называется

инкапсуляцией. Вообще же ООП базируется на трех «китах»:


 инкапсуляция;


 полиморфизм;


 наследование.

Несколько слов об ООП           35

Инкапсуляция проявляет себя во всей красе в виде концепции классов

и объектов. Мы уже обсуждали особенности классов и объектов. Здесь

снова напомним, как они соотносятся: класс является описанием объекта

и полностью определяет содержимое и поведение объекта. Объект созда-

ется на основе класса. Таким образом, в объекте «спрятаны» данные и про-

граммный код методов, которые имеют доступ к этим данным и могут их

обрабатывать. Объекты также взаимодействуют друг с другом. На первый

взгляд такой подход может показаться искусственно усложненным и даже

где-то неприятным, но это только первое впечатление. Впоследствии мы

убедимся, что с классами и объектами работать просто и приятно.

Чтобы понять всю эту небесную механику с классами и объектами, нам

предстоит к классам и объектам привыкнуть (это раз) и научиться ими

пользоваться (это два). Привыкать мы уже начали, а пользоваться

научимся.

Что касается полиморфизма, здесь главная идея состоит в том, чтобы уни-

фицировать однотипные действия, сведя к минимуму количество исполь-

зуемых методов. На практике это сводится к тому, что методы, выполняю-

щие схожие действия, называются одним именем, даже если действия эти

выполняются над данными разных типов.

ПРИМЕЧАНИЕ Полиморфизм базируется на перегрузке и переопределении методов.

Эти нехитрые процедуры мы будем обсуждать позже.

Термин « наследование» достаточно точно характеризует себя. Если кратко, то благодаря наследованию новые классы можно создавать на основе уже

существующих. Это очень сильно экономит время и силы, а также повы-

шает устойчивость и совместимость программного кода. Каждый из упо-

мянутых трех механизмов мы будем исследовать, только, быть может, без

прямого упоминания красивых и загадочных названий этих механизмов.

Ведь инкапсуляция, полиморфизм и наследование — это лишь общие идеи.

Нас же интересуют конкретные способы их реализации. О них, собствен-

но, и будет идти речь в книге.

Конечно, в ООП не все так гладко, как об этом пишут в книгах. У ООП есть

критики, причем вплоть до полного его неприятия. Но поскольку у нас

выхода другого нет (ведь в C# реализуется парадигма ООП), мы воспри-

нимаем ООП как данность и искренне верим в то, что ООП — это новый

и исключительно прогрессивный этап в развитии программирования.

36

Глава 1. Информация к размышлению: язык C# и даже больше

Нередко  применительно  к  среде  .NET  Framework  (и  языку  C#,  как

немаловажной  его  составляющей)  употребляют  такой  термин,  как

«компонентное программирование» или «компонентно-ориенти ро-

ван ное программирование». Некоторые специалисты даже считают

ком по нент но-ориентированное программирование парадигмой, кото-

рая приходит на смену ООП или является надстройкой к ООП. В двух

словах, ком по нент но-ори енти ро ван ное программирование принци-

пиально отличается от обычного ООП системой ограничений и правил, которые  применяются  к  методам  ООП  для  создания  программных

компонентов.  Изюминка  подхода  связана  с  тем,  что  компоненты

могут  быть  написаны  на  разных  языках  программирования.  Язык

C#  содержит  встроенные  средства  для  поддержки  компонентного

программирования.

Еще одна простая программа

Простота есть главное условие

красоты моральной.

Л. Толстой

Здесь мы рассмотрим еще один небольшой пример, который принципи-

ально отличается от предыдущего тем, что в этом примере объявляется

переменная. Кроме того, здесь мы увидим, как с помощью диалоговых окон

реализуется система ввода/вывода.

Программа очень незатейливая. Сначала появляется диалоговое окно с по-

лем ввода, в котором пользователю предлагается указать свое имя. В сле-

дующем окне выводится приветствие для пользователя. В тексте привет-

ствия используется введенная пользователем информация.

Рассматриваемый далее программный код показателен тем, что на-

глядно  демонстрирует  «космополитизм»  языка  C#.  Ведь  для  ото-

бражения окна с полем ввода мы воспользуемся соответствующей

утилитой из средств программирования языка Visual Basic.

Перейдем же от слов к делу и рассмотрим во всех деталях программный

код, представленный в листинге 1.2.

Листинг 1.2.  Еще одна простая программа

using System.Windows.Forms;

using Microsoft.VisualBasic;

Еще одна простая программа           37

class SayHello{

// Главный метод программы:

static void Main(){

// В эту текстовую переменную запишем имя:

string name;

// Отображение окна с полем ввода:

name=Interaction.InputBox("Как Вас зовут?",

"Давайте познакомимся");

// Текст приветствия:

string msg = "Очень приятно, " + name + "!";

// Текст заголовка окна приветствия:

string title = "Окно приветствия";

// Отображение окна приветствия:

MessageBox.Show(msg,title,MessageBoxButtons. OK,

MessageBoxIcon.// Warning);

}

}

Чтобы  покопаться  в  сокровищнице  Visual  Basic  одной  инструкции

using Microsoft.VisualBasic мало. Придется выполнить еще некоторые

нехитрые действия. Необходимо будет добавить соответствующую

ссылку еще и в окне проекта Обозреватель решений. В этом окне

можно проверить, какие ссылки имеются в проекте, — достаточно

раскрыть узел Ссылки, как показано на рис. 1.9.

Нас интересует ссылка Microsoft.VisualBasic, которой в списке ссылок

нет. Именно эту ссылку нам предстоит добавить в проект.

Есть несколько способов добавить ссылку. Все они простые. На-

пример, легко воспользоваться командой Добавить ссылку из меню

Проект. Также легко выделить узел Ссылки в окне Обозреватель ре-

шений и в контекстном меню узла выбрать команду Добавить ссыл-

ку. Но какой бы путь мы ни выбрали, в результате откроется диа-

логовое  окно  Добавить  ссылку,  в  котором  мы  на  вкладке  .NET

находим  и  выделяем  ссылку  Microsoft.VisualBasic,  как  показано

на рис. 1.10.

После  подтверждения  выбора  (щелчок  на  кнопке  OK  в  окне  До-

бавить ссылку), ссылка появится в списке узла Ссылки в окне Обо-

зреватель решений (рис. 1.11).

Точно так же, в случае необходимости, в проект, разрабатываемый

в среде Visual C# Express, добавляются и другие ссылки.

Программный код начинается с двух инструкций подключения про-

странства имен. С одной из них мы уже знакомы: для того, чтобы мож-

но было воспользоваться стандартным окном MessageBox, инструкцией

38

Глава 1. Информация к размышлению: язык C# и даже больше

using System.Windows.Forms подключается пространство имен System.

Windows.Forms. Здесь все более-менее просто. А вот инструкция using Micro soft.VisualBasic является где-то даже экзотической, несмотря на

свой банальный синтаксис. В данном случае мы подключаем простран-

ство имен Microsoft.VisualBasic, благодаря чему получим доступ к стан-

дартному диалоговому окну ввода InputBox, разработанному средствами

программирования Visual Basic.

Рис. 1.9.  Добавляем ссылку в проект

Рис. 1.10.  Выбор ссылки для добавления в проект

Еще одна простая программа           39

Рис. 1.11.  Ссылка Microsoft.VisualBasic добавлена в проект

В главном методе Main() объявляется несколько текстовых переменных.

Текстовая переменная — переменная типа string. Так, если не считать

комментариев, первой командой string name в методе Main() объявляется

переменная name. Кроме этой переменной в программном коде используют-

ся еще две текстовые переменные — переменная msg для хранения текста, который отображается в окне приветствия, и переменная title, в которую

записывается текст для строки заголовка окна приветствия.

Классическое  определение  переменной  —  именованная  область

памяти, обращение к которой выполняется через имя. Другими сло-

вами, если мы используем переменную в программе, это на самом

деле означает, что где-то есть область памяти, в которую значение

можно записать и из которой значение можно считать. Когда в коде

используется переменная (имя переменной), выполняется обращение

к соответствующей области памяти.

В C# переменные объявляются — перед тем как переменную исполь-

зовать, необходимо указать тип переменной и ее имя. Тип переменной

необходимо  указывать,  поскольку  именно  тип  определяет,  какой

объем памяти выделяется под переменную. В C# обычно выделяют

переменные базовых (или простых) типов и объектные переменные.

Что касается типа string, на самом деле это имя класса. Если точнее, ключевое слово string является синонимом названия класса System.

String. Мы обычно не будем делать различия между этими обозначе-

ниями. Поэтому переменная типа string, то есть текстовая переменная, является объектом (точнее, ссылкой на объект класса string). И для

нас все это пока абсолютно не важно.

40

Глава 1. Информация к размышлению: язык C# и даже больше

После того как мы объявили текстовую переменную name, ее можно ис-

пользовать. Значение этой переменной присваивается командой name=

= Inter action.InputBox("Как Вас зовут?","Давайте познакомимся"). Это

команда присваивания. Основу ее составляет оператор присваивания =

(знак равенства). Переменной слева от оператора присваивания (в дан-

ном случае это переменная name) присваивается значение выражения, ука-

занного справа от оператора присваивания. Справа выражение немного

странное, но тем не менее не лишенное смысла. Из класса Interaction вы-

зывается метод InputBox(). Как следствие, на экране появится диалоговое

окно с полем ввода. В качестве результата метода возвращается текстовое

значение, которое пользователь введет в это поле ввода. Собственно, это

значение и записывается в переменную name. Текстовые аргументы метода

InputBox() определяют текст в области окна (текст над полем ввода) и на-

звание для окна (отображается в строке заголовка).

ПРИМЕЧАНИЕ Тестовые значения (литералы) в программном коде заключаются

в двойные кавычки.

Далее следуют две разные, но в то же время и очень одинаковые коман-

ды (если смотреть в корень): string msg="Очень приятно, "+name+"!"

и string title="Окно приветствия". В обоих случаях объявляются и одно-

временно с объявлением инициализируются текстовые переменные msg и title. С переменной title вообще все просто — в качестве значения пере-

менной указан текст в двойных кавычках. Значение переменной msg вычис-

ляется несколько сложнее: объединяется в одну строку текст "Очень при­

ятно, ", текстовое значение переменной name и текст "!".

ПРИМЕЧАНИЕ Если оператор сложения «+» применяется по отношению к текстовым

строкам, в результате мы имеем новую строку, которая получается

объединением соответствующих текстовых фрагментов.

Также обратите внимание на то, что текстовым переменным msg и title значение  присваивается  одновременно  с  их  объявлением.  Для  C#

это нормальная практика, причем не только в отношении текстовых

значений. Более  того,  значение переменной msg  определяется на

основе значения переменной name. Это так называемая динамиче-

ская инициализация переменной — при объявлении переменной ей

присваивается значение, вычисляемое на основе значения другой

переменной  (или  переменных).  Переменные,  на  основе  которых

выполняется динамическая инициализация, должны быть предвари-

тельно описаны, и им должно быть присвоено значение.

Еще одна простая программа           41

Окно приветствия отображается командой MessageBox.Show(msg,title,Mes sageBoxButtons.OK,MessageBoxIcon.Warning). В принципе, с методом Show() класса MessageBox мы уже знакомы, но здесь аргументы передаются методу

несколько специфично. Первые два текстовых аргумента определяют, со-

ответственно, текст, который будет отображаться в окне приветствия (пе-

ременная msg), и заголовок окна приветствия (переменная title). Следую-

щие два аргумента — константы, которые определяют количество кнопок

в окне и тип пиктограммы, которая отображается в области окна вместе

с текстом.

Константа  от  обычной  переменной  отличается  тем,  что  значение

переменной в программном коде изменить можно, а значение кон-

станты — нельзя.

Константа OK является одним из возможных значений перечисления Message BoxButtons и означает, что в окне будет всего одна кнопка — кнопка

OK.

Перечисление — это особый тип данных. Переменная, которая от-

носится к типу перечисления, может принимать одно из значений-

констант,  входящих  в  перечисление.  Каждая  константа  из  пере-

числения  имеет  собственное  имя.  Это  имя  указывается  вместе

с  именем  перечисления  —  через  точку.  Например,  инструкция

MessageBoxButtons.OK  означает  константу  OK  из  перечисления

MessageBoxButtons.  Перечисления  мы  будем  обсуждать  отдельно, но несколько позже. Пока нам важно запомнить, какую константу

в каких случаях можно использовать.

В свою очередь, константа Warning из перечисления MessageBoxIcon озна-

чает, что в области окна будет отображаться пиктограмма «предупрежде-

ния»: восклицательный знак в желтом треугольнике.

ПРИМЕЧАНИЕ Раньше нам уже встречался термин «перегрузка методов». В данном

случае мы имеем дело как раз с ней: при вызове метода Show() аргу-

менты ему можно передавать по-разному, что значительно облегчает

работу программиста.

При запуске программы на экране появляется диалоговое окно, как на

рис. 1.12.

42

Глава 1. Информация к размышлению: язык C# и даже больше

Рис. 1.12.  Окно с полем ввода имени пользователя

В поле ввода этого окна указываем имя и щелкаем на кнопке OK. В резуль-

тате первое окно закроется, а вместо него появится второе (рис. 1.13).

Рис. 1.13.  Окно приветствия с именем пользователя

В  окне  с  полем  ввода  (см.  рис.  1.12)  кроме  кнопки  OK  есть  еще

и кнопка Отмена. Если щелкнуть на кнопке Отмена, окно будет за-

крыто, а в качестве результата возвращается пустая текстовая строка, которая и будет записана в переменную name. Как следствие, второе

окно появится, но в том месте, где в тексте должно быть имя пользо-

вателя, не будет ничего.

Консольная программа

— Что за вздор. Как вам это в голову взбрело?

— Да не взбрело бы, но факты, как говорится,

упрямая вещь.

Из к/ф «Чародеи»

Хотя программирование консольных приложений на C# и считается дур-

ным тоном, попытаться обойти вопрос создания программы, в которой ин-

формация вводится и выводится через консоль, было бы с нашей стороны

слишком самонадеянно.

Консольная программа           43

ПРИМЕЧАНИЕ Консоль — это такое окно, выдержанное в темных тонах, которое

вызывает  ностальгию  по  старым  добрым  временам  операционной

системы MS-DOS.

Несмотря на то, что рассматриваемая далее программа реализует древний

консольный ввод/вывод, в ней мы познакомимся со многими полезными

синтаксическими конструкциями языка C#. Среди них:


 оператор цикла do­while();

 условный оператор if();


 оператор выбора switch();

 блок try­catch обработки исключительных ситуаций;

 ряд других интересных инструкций.

Если представленное дальше покажется несколько удручающим и со-

вершенно непонятным — не стоит впадать в отчаяние. Здесь мы только

знакомимся с некоторыми синтаксическими конструкциями. В крайнем

случае, процедуру знакомства можно проигнорировать. Основы син-

таксиса языка C# обсуждаются более детально в следующих главах.

В программе реализуется простенький калькулятор, который может по-

следовательно выполнять всего четыре действия: сложение, вычитание, умножение и деление. Принцип взаимодействия пользователя с програм-

мой через консольное окно следующий. Пользователь вводит число, затем

символ операции (один из символов «+» (сложение), «­» (вычитание), «*»

(умножение) или «/» (деление)) и новое число. С введенными числами

выполняется соответствующая операция, а пользователь может ввести

символ следующей операции и новое число, и т. д., пока пользователь вме-

сто символа операции не введет ключевое слово exit. Код этой программы

приведен в листинге 1.3.

Листинг 1.3.  Консольная программа - калькулятор

using System;

class Calculator{

// Главный метод программы:

static void Main(){

// Переменные для запоминания

// числовых значений:

double res=0, num;

// Символьная переменная для

// запоминания оператора:

char op = '+';

продолжение

44

Глава 1. Информация к размышлению: язык C# и даже больше

Листинг 1.3 (продолжение)

// Текстовая переменная для

// запоминания ввода пользователя:

string text="";

// Отображение текста в консольном окне:

Console.WriteLine("Начинаем вычисления. Завершение - exit.");

// Блок контроля исключительных ситуаций:

try{

// Оператор цикла:

do{

// Приглашение ввести число:

Console.Write("Ведите число:\t");

// Считывание числа:

num = Double.Parse(Console.ReadLine());

// Оператор выбора:

switch(op){ // Перебор вариантов

// Сложение:

case '+':

res=res+num;

break;

// Вычитание:

case '-':

res=res­num;

break;

// Умножение:

case '*':

res=res*num;

break;

// Деление:

case '/':

res=res/num;

break;

}

// Отображение текущего значения:

Console.WriteLine("Результат:\t"+res);

// Приглашение для ввода символа операции:

Console.Write("Операция:\t");

// Считывание текста:

text=Console.ReadLine();

// Условный оператор - проверка

// команды выхода:

if(text.Equals("exit")) break;

// Попытка определить символ:

op=Char.Parse(text);

// Условный оператор - проверка

// символа операции:

if(!(op=='+'|op=='-'|op=='*'|op=='/')){

Консольная программа           45

// Отображение сообщения и завершение

// работы оператора цикла:

Console.WriteLine("Такая операция недопустима!"); break;

}

// Условие продолжения цикла:

}while (true);

}catch{

// Обработка исключительной ситуации:

Console.WriteLine("Выполнена недопустимая команда.");

}

// Сообщение о завершении работы программы:

Console.Write("Вычисления закончены. Нажмите клавишу Enter...");

// Ожидание нажатия клавиши Enter:

Console.ReadLine();

}

}

В среде Visual C# Express создаем консольное приложение. Для этого

в  окне  создания  нового  проекта  Создать  проект  выбираем  пункт

Консольное приложение, как показано на рис. 1.14.

Рис. 1.14.  Создание консольного приложения

Дальше все практически так же, как и в случае создания приложения

с графическим интерфейсом. Однако в консольном приложении форм

нет, поэтому ничего удалять не придется.

46

Глава 1. Информация к размышлению: язык C# и даже больше

Командой using System подключается пространство имен System. Это

необходимо сделать для того, чтобы стали доступными методы класса

Console для работы с консольным устройством. В частности, речь идет

о методах Write(), WriteLine() и ReadLine(), которые вызываются с ука-

занием класса Console. Первые два метода выводят на экран текстовое

значение, указанное аргументом. Разница между этими методами состо-

ит в том, что при использовании метода WriteLine() курсор вывода пере-

водится в новую строку (после завершения вывода), а для метода Write() он остается в той же строке. С помощью метода ReadLine() считывается

текстовая строка, введенная пользователем. Метод вызывается без аргу-

ментов.

ПРИМЕЧАНИЕ Признаком того, что мы закончили ввод текстовой строки, является

нажатие клавиши Enter. При этом вся строка считывается в текстовом

формате — даже если мы ввели число, считано оно будет как текст.

Как с этим бороться, рассказано далее.

В начале программы мы объявляем две переменные (res и num) типа double.

Этот тип соответствует действительным числам в формате представления

с плавающей точкой. При этом переменная res сразу в качестве началь-

ного получает нулевое значение. В эту переменную мы будем записывать

результат вычислений. В переменную num будет записываться очередное

введенное пользователем число. Также нам понадобится символьная пере-

менная (переменная типа char) для записи символа операции. Эта пере-

менная называется op, и ее начальное значение равно '+'. Таком образом, первая операция — это сложение.

ПРИМЕЧАНИЕ Значение символьной переменой — это символ (или буква, если под

буквой подразумевать любой символ). Символьный литерал (буква) заключается в одинарные кавычки. Если букву заключить в двойные

кавычки, это будет текстовый литерал.

Нормальный режим завершения работы программы предполагает, что вме-

сто символа операции мы вводим слово exit. Это текст. Поэтому на каж-

дом этапе, когда предполагается прочитать с консоли символ оператора, мы будем считывать текст, а затем этот текст будем обрабатывать. Текст

запоминаем в переменной text, начальным значением которой является

пустая текстовая строка. После отображения приветственного сообщения

"Начинаем вычисления. Завершение - exit." в консоли, которое выводится

с помощью статического метода WriteLine() класса Console, запускается

оператор цикла do­while().

Консольная программа           47

Практически весь последующий код заключен в блок try — после

этого ключевого слова в фигурных скобках размещен обсуждаемый

далее программный код. После try-блока можно обнаружить catch-

блок. На самом деле это две составные части одной конструкции, главное и благородное назначение которой — обработка исключи-

тельных ситуаций, то есть ошибок, которые возникают в процессе

выполнения  программы.  Назначение  блока  try-catch  мы  обсудим

более детально несколько позже.

Начинается оператор цикла ключевым словом do и заканчивается инструк-

цией while(true). Формально это означает бесконечный цикл. Команды, размещенные внутри тела оператора цикла, в данном конкретном случае

могли бы выполняться бесконечно долго (если бы мы не предусмотрели

хитроумную процедуру выхода).

Оператор  цикла  do-while()  выполняется  следующим  образом:  вы-

полняются команды тела цикла (команды в фигурных скобках после

ключевого  слова  do),  после  чего  проверяется  условие,  указанное

в круглых скобках после ключевого слова while. Условие — это вы-

ражение логического типа (тип bool). Переменная этого типа может

принимать всего два значения — true (истина) или false (ложь). Если

условие истинно (значение выражения равно true), работа оператора

цикла продолжается — будут выполнены команды тела цикла, и за-

тем снова проверяется условие, и т. д. Поскольку в нашем случае

условием  указано  ключевое  слово  true,  условие  всегда  истинно.

Поэтому формально имеем дело с бесконечным циклом. На самом

деле, конечно, цикл завершится за конечное количество итераций.

В этом мы убедимся при анализе программного кода и тестировании

программы.

Командой Console.Write("Ведите число:\t") в консольное окно выводится

сообщение с приглашением ввести число. При этом в тексте использована

инструкция табулирования \t — чтобы результат вывода текстовой инфор-

мации в консольном окне выглядел упорядоченно. После этого командой

num=Double.Parse(Console.ReadLine()) считываем число, введенное поль-

зователем. Здесь нужны некоторые пояснения. Посредством инструкции

Console.ReadLine() в текстовом формате считывается то, что ввел пользо-

ватель. Мы предполагаем, что это число. Вместе с тем речь идет о текстовом

представлении числа. Именно это текстовое представление числа возвра-

щается в качестве результата инструкции. Нам необходимо текстовое пред-

ставление числа трансформировать в числовое значение — значение типа

double. Для этого предназначен статический метод Parse в классе Double.

48

Глава 1. Информация к размышлению: язык C# и даже больше

Аргументом метода Parse() мы передаем инструкцию Console.ReadLine(). Ре-

зультатом выражения Double.Parse(Console.ReadLine()) является числовое

значение типа double. Именно это значение записываем в переменную num.

ПРИМЕЧАНИЕ Вся эта конструкция работает, если мы действительно ввели число.

Если  мы  ввели  не  число,  возникнет  ошибка.  Из-за  такой  ошибки

в  принципе  работа  программы  завершается.  Другое  дело,  что  вся

интрига закручивается внутри блока try, поэтому даже такая ошибка

не остановит работу программы.

Для проверки значения переменной op мы используем оператор выбора

switch(). Аргументом указывается переменная op, а проверяются совпа-

дение значения этой переменной со значениями '+' (сложение), '­' (вы-

читание), '*' (умножение) и '/' (деление). Соответствующие значения

указываются в case-блоках. Каждый case-блок заканчивается инструкцией

break. Значение переменной op последовательно сравнивается со значени-

ями, указанными в case-блоках. Если совпадение найдено, выполняются

команды соответствующего блока. Если совпадение не найдено, ничего не

выполняется.

ПРИМЕЧАНИЕ В данном случае у нас есть две переменные: результат предыдущих

вычислений res и вновь введенное значение num. В зависимости от

того, какой символ операции введен, выполняется заданная операция.

Операндами являются переменные res и num.

Когда нужная операция выполнена, командой Console.WriteLine("Резуль-

тат:\t"+res) отображается текущий результат вычислений. Сразу после

этого появляется приглашение ввести символ операции (команда Console.

Write("Операция:\t")). Введенный текст считывается с консоли и записы-

вается в переменную text. Для этого мы используем команду text=Console.

ReadLine(). Это значение нам нужно протестировать, для чего используем

условные операторы.

У условного оператора синтаксис вызова следующий:

if(условие){команды}

else {команды}

В круглых скобках после ключевого слова if указывается условие.

Если условие истинно, выполняются команды в фигурных скобках

после  if-инструкции.  Если  условие  ложно,  выполняются  команды

в фигурных скобках после ключевого слова else. Есть сокращенная

форма условного оператора, в которой else-блок не используется.

Консольная программа           49

Сначала мы проверяем, введен ли пользователем текст "exit". Для срав-

нения текстовых значений переменной text и литерала "exit" используем

метод Equals(), который вызывается из объекта text. Вся инструкция вы-

глядит как text.Equals("exit"). Результатом является true, если тексто-

вое значение переменной text совпадает с литералом "exit". В противном

случае результат равен false.

Как уже отмечалось, string — это как бы имя класса. Переменная

типа string на самом деле является объектом класса string. У этого

объекта, как и у любого объекта класса string, имеется метод Equals(), позволяющий сравнивать текстовое значение объекта, из которого

вызывается  метод,  и  текстовое  значение,  переданное  аргументом

методу.  Сравнение  текстовых  значений  выполняется  с  учетом  со-

стояния регистра (строчные и прописные буквы считаются разными

символами).

В случае если значение текстовой переменной text равно "exit", выпол-

няется инструкция break, которая завершает работу оператора цикла dowhile(), а управление передается следующему оператору после опера-

тора цикла. Именно благодаря инструкции break в условном операторе

формально бесконечный циклический оператор не является на самом деле

бесконечным. После выхода из оператора цикла будут выполнены последо-

вательно инструкции Console.Write("Вычисления закончены. Нажмите кла­

вишу Enter...") и Console.ReadLine(). Первая из этих инструкций просто

выводит сообщение о том, что выполнение программы завершено. Вторая

формально является инструкцией считывания консольного ввода пользова-

теля. Но здесь она играет совершенно особую роль — с помощью этой ин-

струкции мы удерживаем консольное окно на экране до нажатия клавиши

Enter.

Когда  программа  завершает  работу,  консольное  окно  автоматиче-

ски закрывается. Поскольку выполняется программа очень быстро, мы можем и не заметить, что это окно вообще открывалось. А если

и заметим, то вряд ли сможем оценить содержимое окна. Поэтому

мы проявляем военную хитрость — добавляем инструкцию Console.

ReadLine(),  которая  формально  означает  считывание  введенного

пользователем текста. Но этот текст никуда не записывается и сам

по себе нас не интересует. Это лишь повод не закрывать консольное

окно.

Если пользователь не ввел команду exit, команда break в условном опера-

торе не выполняется и оператор цикла продолжает свою работу. Командой

50

Глава 1. Информация к размышлению: язык C# и даже больше

op=Char.Parse(text) выполняется попытка преобразовать значение тек-

стовой переменной в text в символьное значение. Для этого используется

статический метод Parse() класса Char. Аргументом указывается перемен-

ная text. Затем на сцену выходит еще один условный оператор. В нем про-

веряется сложное условие !(op=='+'|op=='-'|op=='*'|op=='/'). Восклица-

тельный знак ! является оператором логического отрицания. Вертикальная

черта | является оператором логического или. Двойное равенство == есть не

что иное, как логический оператор равенства. Поэтому, например, выраже-

ние op=='+' равно true, если значение переменной op равно '+', и false, если

не равно. Выражение op=='+'|op=='-' равно true, если значение переменной

op равно '+' или '­' (и false во всех остальных случаях). Значение выраже-

ния op=='+'|op=='-'|op=='*'|op=='/' равно true, если переменная op равна

'+', или равна '­', или равна '*', или равна '/'. Оператор логического отри-

цания ! превращает true в false и false в true. Поэтому значением выраже-

ния !(op=='+'|op=='-'|op=='*'|op=='/') будет true, только если переменная

op не равна ни одному из символьных значений '+', '­', '*' или '/'. Други-

ми словами, значение выражения равно true, если мы ввели неправильный

символ операции. В этом случае благодаря условному оператору выводится

текстовое сообщение "Такая операция недопустима!" и инструкцией break завершается работа оператора цикла. Еще один способ цивилизованно вый-

ти из бесконечного циклического процесса — ввести некорректный символ

арифметической операции.

Блок try-catch предназначен, как уже отмечалась, для обработки ис-

ключительных ситуаций. Исключительная ситуация — это ошибка, которая возникает в процессе выполнения программы. В C# очень

элегантная  и  мощная  встроенная  система  обработки  ошибок.  Ба-

зируется она как раз на конструкции try-catch. Основная идея, за-

ложенная в процедуру обработки ошибок, достаточно проста и эле-

гантна. Программный код, который может при выполнении вызвать

ошибку,  заключается  в  блок  try.  После  try-блока  обычно  следует

несколько catch-блоков. Каждый catch-блок предназначен для об-

работки ошибки определенного типа. Если в try-блоке в процессе

выполнения программы возникает ошибка, код try-блока перестает

выполняться, а вместо этого выполняется код соответствующего типу

ошибки catch-блока. В рассматриваемом примере использован всего

один catch-блок, который предназначен для обработки всех ошибок, которые могут возникнуть при выполнении программы.

Нам осталось разобрать только программный код в catch-блоке. Там всего

одна инструкция Console.WriteLine("Выполнена недопустимая команда."), которая выполняется, если при выполнении команд в блоке try возникнет

ошибка — любая. Если ошибка возникла, выполнение команд в try-блоке

Консольная программа           51

прекращается и выполняются команды в catch-блоке. После этого выпол-

няются команды, которые находятся после конструкции try­catch. Если

же при выполнении try-блока ошибки не возникают, catch-блок не выпол-

няется. С помощью такой нехитрой конструкции мы обеспечиваем более

устойчивую работу программы.

Протестируем работу программы. Для начала выделим несколько показа-

тельных ситуаций:


 если вместо символа операции мы введем слово exit, работа программы

будет завершена;


 если мы введем некорректный символ операции, работа программы будет

завершена;


 если мы введем некорректное число, программа будет завершена.

Реализуем каждую из этих гипотетических ситуаций. На рис. 1.15 показа-

на ситуация, когда работа программы завершается вследствие ввода клю-

чевого слова exit.

Рис. 1.15.  Работа программы завершена инструкцией exit На рис. 1.16 проиллюстрировано, что произойдет, если мы введем некор-

ректный символ для арифметической операции.

Рис. 1.16.  Работа программы прекращена из-за некорректного символа

арифметической операции

52

Глава 1. Информация к размышлению: язык C# и даже больше

Наконец, реакция программы на некорректное числовое значение показа-

на на рис. 1.17.

Рис. 1.17.  Работа программы прекращена из-за некорректного числа

Желающие могут еще поупражняться в работе программы и подвергнуть

ее всевозможным испытаниям. У нас же есть более важные задачи, к реше-

нию которых мы приступим в следующей главе.

Классы и объекты

Хотите обмануть мага? Боже, какая

детская непосредственность. Я же вижу

вас насквозь.

Из к/ф «31 июня»

С классами мы уже сталкивались — собственно, ни одна наша программа

не обошлась без класса. Об объектах речь тоже уже шла. Но назвать это

знакомством с классами и объектами было бы с нашей стороны несколько

самонадеянно. Здесь мы постараемся систематизировать и привести в толк

наши познания в данной области. Мы это сделаем, поскольку альтернати-

вы у нас нет — без классов и объектов о программировании в C# можно

и не мечтать.

Описание класса

Это экспонаты. Отходы, так сказать,

магического производства.

Из к/ф «Чародеи»

Мы уже примерно представляем, что такое класс. Во всяком случае, классы

мы использовали каждый раз, когда писали программу. Вместе с тем каж-

дый раз у нас был лишь один класс, причем довольно специфический —

для этого класса мы не создавали объекты. Главное его предназначение

54

Глава 2. Классы и объекты

состояло в том, что в классе описывался метод Main(), во многих отноше-

ниях отождествляемый с программой. В этой главе мы перейдем на ка-

чественно новый уровень программирования — наши программы будут

содержать несколько классов. Также мы узнаем, как на основе классов соз-

даются объекты — ведь в конечном счете именно для создания объектов

нужен класс.

ПРИМЕЧАНИЕ Это не всегда так. Есть классы, которые представляют интерес сами

по себе, без всяких там объектов. Обычно это классы со статическими

методами, которые играют роль библиотеки.

В этой главе мы расширим свои познания в области создания классов.

Классы могут быть самыми разными, но нас пока интересуют наиболее

простые варианты. В ближайшем будущем мы будем использовать следую-

щий шаблон для создания классов:

class имя_класса{

public тип_поля имя_поля;

public тип_результата имя_метода(аргументы){

// код метода

}

}

ПРИМЕЧАНИЕ Члены класса (в данном случае поля и методы) могут быть закрытыми

и открытыми. Закрытые члены класса — это члены, которые класс

приберегает «для себя», то есть для использования исключительно

в пределах класса. Открытые члены класса можно использовать не

только внутри класса, но и вне его. Именно такие члены класса пока

что нас и будут интересовать.

Блок с кодом класса начинается ключевым словом class, после которого

указывается имя класса, а тело класса заключается в фигурные скобки.

Собственно класс — то, что находится в фигурных скобках. А в скобках

может находиться описание полей и методов (и некоторых членов класса).

Поля описываются как обычные переменные: указывается тип переменной

и ее имя. Описание метода выполняется по такому шаблону:

 идентификатор типа результата — ключевое слово, которое определяет

тип значения, возвращаемого методом в качестве результата;

 имя метода;

Описание класса           55


 в круглых скобках указывается список аргументов. Аргументы пере-

числяются через запятую, для каждого аргумента указывается тип. Если

аргументов нет, скобки все равно есть — пустые;


 программный код метода (тело метода) заключается в фигурные скобки.

И поля, и методы описываются с ключевым словом public, что означает их

доступность за пределами класса.

В качестве иллюстрации рассмотрим программный код с описанием клас-

са, представленный в листинге 2.1.

Листинг 2.1.  Класс с полем и двумя методами

class MyClass{

// Поле класса:

public string name;

// Метод класса для присваивания "имени":

public void SetName(string arg){

// Присваиваем значение полю name:

name=arg;

// Отображаем сообщение об изменении

// значения поля name:

Console.WriteLine("Присвоено значение полю name.");

}

// Метод класса для отображения "имени":

public void ShowName(){

// Отображаем сообщение со значением

// поля name:

Console.WriteLine("Значение поля name: "+name);

}

}

Наш класс называется MyClass. У класса одно поле и два метода. Поле называ-

ется name, и это поле текстовое — оно объявляется как переменная типа string.

Что касается методов, то оба они не возвращают результат. Поэтому в каче-

стве идентификатора типа результата использовано ключевое слово void.

У метода SetName() один текстовый аргумент (объявлен как string arg).

В теле метода командой name=arg полю name присваивается значение, как у ар-

гумента arg. Затем командой Console.WriteLine("Присвоено значение полю

name.") в консоль выводится сообщение с информацией о том, что значе-

ние поля name изменено.

У метода ShowName() аргументов нет. Единственной командой Console.

Write Line("Значение поля name: "+name) в теле метода отображается кон-

сольное сообщение с информацией о значении поля name.

56

Глава 2. Классы и объекты

ПРИМЕЧАНИЕ В методах почти массово используется обращение к полю name. Ре-

зонным образом возникает вопрос, о поле name какого объекта идет

речь? Ведь у каждого объекта класса есть поле name. Поэтому сколько

объектов класса, столько разных полей, и каждое называется name.

Но проблемы здесь на самом деле нет — обращение выполняется

к полю того объекта, из которого вызывается метод.

На этом описание класса заканчивается, и остается лишь проверить, какая

от этого класса может быть польза. Нам предстоит несколько расширить

программный код. Он будет содержать не только описание класса, но и ин-

струкции по созданию объектов на основе этого класса.

Объектные переменные

и создание объектов

Очень убедительно. Мы подумаем,

к кому это применить.

Из к/ф «31 июня»

Нам предстоит еще одно усилие на пути изучения классов — мы будем

создавать объекты. В C# процедура создания объекта (в широком смысле

этого понятия) имеет некоторые особенности, если сравнивать, например, с созданием обычной переменной (не объекта). Условно процесс создания

объекта можно разбить на два этапа:


 создание объектной переменной;


 создание объекта с присваиванием значения объектной переменной.

Строго  говоря,  при  создании  объекта  указывается  не  имя  класса, а конструктор класса. Конструктор класса — это такой специальный

метод. Одна из его особенностей состоит в том, что имя конструктора

совпадает с именем метода. Даже если мы конструктор в классе не

описывали, он все равно существует — это так называемый конструк-

тор по умолчанию. У такого конструктора нет аргументов — отсюда

и пустые круглые скобки после имени класса в инструкции создания

объекта. Мы расставим все точки над i в вопросе создания объектов

после  того,  как  поближе  познакомимся  с  конструкторами,  интер-

фейсами и наследованием. Другими словами, вопрос этот не такой

тривиальный, как может показаться на первый взгляд.

Объектная переменная создается абсолютно так же, как и «необъектная»

переменная, с той лишь разницей, что в качестве идентификатора типа

Объектные переменные и создание объектов           57

указывается имя класса, для которого создается объектная переменная.

Например, чтобы создать объектную переменную с именем obj для класса

MyClass, можем воспользоваться командой MyClass obj. Однако объектная

переменная — это еще не объект (хотя именно с помощью объектной пере-

менной мы будем обращаться к объекту и выполнять с ним все основные

операции). Для создания непосредственно объекта используем оператор

new. Чтобы было понятно, какого класса объект создается, после оператора

new указывается имя класса с пустыми круглыми скобками.

Например, для создания объекта класса MyClass можно воспользоваться

инструкцией new MyClass(). Использование такой инструкции имеет два

важных следствия:


 во-первых, создается объект класса MyClass;


 во-вторых, в качестве результата возвращается адрес этого объекта, или

ссылка на объект.

Если есть результат, то его обычно куда-то записывают. Адреса объектов

(ссылки на объект) записывают в объектные переменные (обычно класс

объектной переменной должен совпадать с классом объекта). Собственно, объектная переменная и создается для того, чтобы в нее записать ссылку на

объект. В этом смысле вполне логичными могли бы быть такие команды: MyClass obj;

obj=new MyClass();

Благодаря этим двум инструкциям в наше распоряжение поступает объект

класса MyClass, доступ к которому мы имеем через переменную obj. В даль-

нейшем, если это не будет приводить к недоразумениям, под объектом мы

будем подразумевать как раз объектную переменную.

ПРИМЕЧАНИЕ Инструкции по созданию объектной переменной и объекта можно

объединить в одну — совместить объявление объектной перемен-

ной и создание объекта. Так, альтернативой командам MyClass obj и  obj=new  MyClass()  может  быть  одна-единственная  команда

MyClass obj=new MyClass().

Теперь мы практически готовы к тому, чтобы применить объекты на прак-

тике. Расправим наши крылья, воспользовавшись программным кодом, представленным в листинге 2.2.

Листинг 2.2.  Название листинга

using System;

class MyClass{

// Поле класса:

public string name;

продолжение

58

Глава 2. Классы и объекты

Листинг 2.2 (продолжение)

// Метод класса для присваивания "имени":

public void SetName(string arg){

// Присваиваем значение полю name:

name=arg;

// Отображаем сообщение об изменении

// значения поля name:

Console.WriteLine("Присвоено значение полю name.");

}

// Метод класса для отображения "имени":

public void ShowName(){

// Отображаем сообщение со значением поля name:

Console.WriteLine("Значение поля name: "+name);

}

}

// Класс с методом Main():

class ObjDemo{

// Главный метод программы:

public static void Main(){

// Объектная переменная класса MyClass:

MyClass cat;

// Создание объекта класса MyClass:

cat=new MyClass();

// Создание объекта и переменной класса MyClass:

MyClass dog=new MyClass();

// Полю name объекта cat присваивается значение:

cat.name="Мурчик";

// Полю name объекта dog присваивается значение:

dog.SetName("Шарик");

// Отображается значение поля name объекта cat:

cat.ShowName();

// Отображается значение поля name объекта dog:

dog.ShowName();

Console.ReadLine();

}

}

Метод  Main()  мы  описали  с  атрибутом  public.  Здесь  мы  последо-

вали  общей  рекомендации:  описывать  главный  метод  программы

как открытый. Вместе с тем и без этого атрибута программа будет

работать.

Это полный программный код, в котором, помимо уже знакомого нам

класса MyClass, есть еще один класс, ObjDemo, в котором описан метод

Объектные переменные и создание объектов           59

Main(). В этом методе, в свою очередь, создаются и используются объек-

ты класса MyClass. Поскольку программный код класса MyClass мы уже

анализировали, остановим свое внимание на программном коде метода

Main(). Вкратце сюжет пьесы такой. Создается два объекта cat и dog клас-

са MyClass. Полям name этих объектов присваиваются значения, после чего

значения этих полей выводятся в консоль. Объект cat создается в два

этапа. Сначала командой MyClass cat объявляется объектная переменная

класса MyClass. Непосредственно создание объекта класса MyClass и при-

сваивание ссылки на этот объект переменной cat выполняется командой

cat=new MyClass(). Создание второго объекта выполняется с помощью ко-

манды MyClass dog=new MyClass(). Здесь и объектная переменная создает-

ся, и объект, и ссылка на объект присваивается объектной переменной.

На следующем витке эволюции полям новоиспеченных объектов при-

сваиваются значения. Для объекта cat мы используем простую прямую

команду cat.name="Мурчик". Здесь мы встречаемся с примером точечного

синтаксиса. Это классика жанра — для ссылки на поле name объекта cat мы указываем имя объекта и, через точку, имя поля. Присваиваемое полю

значение указано справа от оператора присваивания. По-другому мы по-

ступаем с объектом dog. Для этого командой dog.SetName("Шарик") из объ-

екта dog вызывается метод SetName() с текстовым аргументом, который

присваивается полю name этого объекта. Здесь мы также имеем дело с то-

чечным синтаксисом.

ПРИМЕЧАНИЕ Обратите внимание на то, что в соответствии с кодом метода SetName()  в  консоль  выводится  сообщение  о  присвоении  значения

полю name.

Кульминацией программы являются команды cat.ShowName() и dog.Show­

Name(), которыми в консоль выводятся сообщения о значении полей name соответствующих объектов.

Напоминаем, что команда Console.ReadLine() нужна исключительно

для  того,  чтобы  окно  консоли  не  закрылось  сразу  по  выполнении

предыдущих инструкций.

Результат выполнения программы представлен на рис. 2.1, где показано

консольное окно с сообщениями, которые увидит пользователь.

Это общая схема создания и использования объектов и объектных пере-

менных. Теперь мы будем постепенно усовершенствовать методы работы

с объектами.

60

Глава 2. Классы и объекты

Рис. 2.1.  Результат выполнения программы, в которой использованы объекты

Перегрузка методов

Нет, такой хоккей нам не нужен!

Н. Озеров

Перегрузка методов — весьма полезный и перспективный механизм, ко-

торый позволяет создавать очень гибкие и эффективные методы. В общих

чертах суть перегрузки методов состоит в том, что в классе можно создавать

(описывать) несколько вариантов одного и того же метода. «Несколько ва-

риантов» в данном случае означает, что все эти методы имеют одинаковые

названия, но при этом различаются количеством и (или) типом аргументов.

ПРИМЕЧАНИЕ Процедура перегрузки методов есть не только в C#, но и в C++ и Java.

Во всех случаях общий подход универсален — у перегружаемых ме-

тодов одинаковые названия, но при этом разные варианты методов

должны быть различимы. В принципе идентификацию того или иного

варианта метода (поскольку у всех у них одинаковые названия) мож-

но выполнять на основе списка аргументов и (или) типа результата.

В  C#  такая  идентификация  выполняется  только  на  основе  списка

аргументов метода. У разных версий перегружаемого метода должно

быть  разное  количество  аргументов  или  аргументы  должны  быть

разного типа. Обычно правильная фраза звучит так: «при перегрузке

метода неизменно название, но разная сигнатура». Под сигнатурой

в C# подразумевают имя метода и список его аргументов. Обратите

внимание: тип результата в понятие «сигнатура» не входит!

Реализуется перегрузка метода достаточно просто. Каждый вариант мето-

да описывается как отдельный метод. Важно только помнить, что разные

варианты должны быть различимы на уровне аргументов. Ведь количество

и тип переданных методу аргументов являются индикаторами того, какой

вариант метода необходимо вызывать в том или ином случае. Проиллю-

стрируем это на конкретном примере. Обратимся к программному коду, представленному в листинге 2.3.

Перегрузка методов           61

Листинг 2.3.  Перегрузка методов

using System;

class Person{

// Закрытое числовое поле:

int age;

// Закрытое текстовое поле:

string name;

// Открытый метод для отображения полей:

public void show(){

Console.WriteLine("Имя: "+name);

Console.WriteLine("Возраст: "+age);

}

// Открытый перегруженный метод для

// присваивания значения полям.

// Версия перегруженного метода

// с двумя аргументами:

public void set(int n,string arg){

age=n;

name=arg;

}

// Версия метода без аргументов:

public void set(){

age=0;

name="Нет имени";

}

// Версия метода с одним числовым аргументом:

public void set(int n){

// Вызывается версия метода с двумя аргументами:

set(n,"Нет имени");

}

// Версия метода с одним текстовым аргументом:

public void set(string arg){

// Вызывается версия метода

// с двумя аргументами:

set(0,arg);

}

}

class PersonDemo{

// Главный метод программы:

public static void Main(){

// Создание объекта fellow класса Person:

Person fellow=new Person();

// Вызов версии метода set() с одним

// числовым аргументом:

fellow.set(100);

продолжение

62

Глава 2. Классы и объекты

Листинг 2.3 (продолжение)

// Отображение результата:

fellow.show();

// Вызов версии метода set() с одним

// текстовым аргументом:

fellow.set("Колобок");

// Отображение результата:

fellow.show();

// Вызов версии метода set() с двумя аргументами:

fellow.set(10,"Буратино");

// Отображение результата:

fellow.show();

// Вызов версии метода set() без аргументов:

fellow.set();

// Отображение результата:

fellow.show();

Console.ReadLine();

}

}

Перегруженный метод находим в классе Person. У класса два поля (цело-

численное age и текстовое string) и два метода (show() и set()) — правда, один из этих методов (метод set()) перегружается. Для этого метода опи-

сано четыре различных версии: с двумя аргументами, без аргументов, с од-

ним текстовым аргументом и одним целочисленным аргументом.

ПРИМЕЧАНИЕ Поля у класса тоже не очень простые. Они описаны без ключе-

вого слова public. Такие поля являются закрытыми и недоступны

вне класса. Поэтому в программном коде класса эти поля можно

использовать,  а  вот  обратиться  напрямую  к  полям  вне  класса  не

получится. Например, в главном методе программы создается объ-

ект fellow класса Person. И хотя у объекта fellow есть поля name и  age,  использовать  инструкцию  вида  fellow.name  или  fellow.age не получится.

С методом show() все просто — он нужен для отображения значений по-

лей name и age объекта, из которого вызывается метод. Нас интересует

метод set(). С помощью метода задаются значения полей name и age. Мы

перегружаем метод для того, чтобы можно было по-разному задавать

значения полей объекта. Естественным представляется вариант, когда

мы указываем в качестве аргументов метода set() значения, которые

присваиваются полям объекта. В этом случае первый, числовой, аргу-

мент определяет значение поля age, а второй, текстовый, аргумент задает

значение поля name.

Перегрузка методов           63

Если метод set() вызывается без аргументов, поле age получит нулевое зна-

чение, а значением поля name будет текст "Нет имени". Кроме этого, можно

передать только один аргумент методу set(). Если это числовой аргумент, то соответствующее значение получает поле age. Поле name, которое обде-

лено вниманием при передаче аргументов методу set(), получит значение

"Нет имени". В случае, когда единственный аргумент метода set() тексто-

вый, это текстовое значение будет присвоено полю name объекта. Числовое

поле age получит нулевое значение.

Версии метода set() с двумя аргументами и без аргументов описы-

ваются в явном виде. А вот при описании двух версий метода set() с одним аргументом мы схитрили — в теле перегружаемого метода

вызывали версию метода с двумя аргументами. Вообще же следует

понимать, что на самом деле разные версии перегруженного мето-

да — это разные методы. Просто эти методы имеют совпадающие

имена.

В главном методе программы в классе PersonDemo проверяются различные

способы присваивания значений полям объекта fellow класса Parson. Для

присваивания значений полям объекта мы вызываем из объекта метод

set() с разными наборами аргументов. Проверка значений полей объекта

осуществляется командой fellow.show(). Результат выполнения програм-

мы представлен на рис. 2.2.

Рис. 2.2.  Результат выполнения программы с перегруженным методом

ПРИМЕЧАНИЕ Имеет смысл акцентировать внимание еще на одном немаловаж ном

обстоятельстве, которое касается закрытых полей name и age. Как

отмечалось выше, эти поля закрытые и доступа к ним вне объекта

нет. Вместе с тем поля вполне функциональны и доступны к исполь-

зованию. Для доступа к закрытым полям мы используем открытые

методы: у нас есть доступ к открытым методам, а открытые методы

имеют доступ к закрытым полям. На практике это очень удобно.

64

Глава 2. Классы и объекты

Конструкторы и деструкторы

Нам песня строить и жить помогает.

Из к/ф «Веселые ребята»

Сейчас самое время познакомиться с конструкторами и их антиподами

в мире программирования — деструкторами. Здесь нет ничего сложного.

Конструктор — это специальный метод, который вызывается автоматиче-

ски при создании объекта класса. Таким образом, если мы хотим, чтобы

при создании объекта происходило нечто особенное, создаем конструктор.

Деструктор — это метод, который вызывается автоматически при удале-

нии объекта из памяти. По сравнению с конструкторами, деструкторы ис-

пользуются не так часто, но не менее эффектно.

Конструктор описывается практически так же, как обычный метод, но име-

ет некоторые особенности:


 Имя конструктора совпадает с именем класса.


 Конструктор объявляется с атрибутом public (конструктор должен быть

открытым методом).


 Конструктор не возвращает результат, а идентификатор типа результата

для него не указывается.


 У конструктора могут быть аргументы и конструкторы можно перегру-

жать (у класса может быть несколько конструкторов).

Относительно деструктора правила еще более жесткие:


 Имя деструктора — это тильда (символ ~) плюс имя класса.

Загрузка...