Вы находитесь на странице: 1из 1155

~ w w.willfamsрubIisl,ing...оm

Apress
;;
Эндрю Троелсе н
языK ПРОГРАММ'И'РОВАНИЯ
С#'2005
И ПЛАТФОРМА .NET 2.0
3-е из,дание

Эндрю Троелсен

Москва· Санкт-Петербург • Киев


2007
ББК 32.973.26-018.2.75
Т76
УДК 681.3.07

Издательский дом "Вильямс"

Зав. редакцией С.Н. ТрU2уб

Перевод с английского и редакция л.г. Сивака

По общим вопросам обращзйтесь в Издательский дом "Вильямс" по адресу:


info@w1lliamspublisblng.com, http://www.wilНamspublishing.com
115419. Москва, а/я 783; 03150, Киев, а/я 152

Троелсев, Эндрю.

Т76 Язык программирования С# 2005 и платформа .NEТ 2.0. 3-е издание. : Пер.
с англ. - М. : 000 "и.д. Вильямс~. 2007. - 1168 с. : ил. - Парал. ТИ1: ангЛ.
ISBN 5-8459-1124-9 (рус.)

в этой книге содержится описание базовых принципов функционирования плат­


формы .NEТ, системы типов .NEТ и различных инструментальных средств разработ­
ки. используемых при создании приложений . NEТ. Представлены базовые возможно­
СТИ языка программирования С# 2005, ВJ(ЛЮчая новые синтаксические конструкции.
появившиеся с выходом .NEТ2.0, а также синтаксис и семантика язьrn:а CIL. В книге
рассматривается формат сборок .NEТ, библиотеки базовых массов .NEт. файловый
ввод-вывод. возможности удаленного доступа, конструкция приложений Windows
Forms. доступ к базам данных с помощью ADO.NEТ, создание Web-приложений
ASP NEТ и Web-служб XМ:L. Книrа содержит множество примеров программного кода,
призванного помочь читателю в освоении предлагаемого материала. Программный
код примеров можно загрузить с Web-сайта издательства.

ББК 32.973.26-018.2.75

Все названия программных продуктов являются зарегистрированными торговыми маp1«iМИ со­

ответствующих фирм.
Никакая часть настоящего издания ни в к;utИX целях не может быть воспроизведена в какой
бы то ии было форме и какими бы то ни было средствами. будь то электронные или механические,
ВК1IЮЧан фотокопирование и запись на магнитный носитель. если на это нет письменного разреше­
ния издательства APress. Berkeley. СА.

Authorlzed trапslаtiоп from the EnglIsh language edltion pubUshed Ьу ЛPresэ. Inc .• Copyrlght © 2005.
АН rlghts reseгved. No part of thls work тау Ье reproduced ог transmltted lп апу (оrш ог Ьу anу
теans. electroDic or mechanlcal, lnclud!ng photocopy!ng. recordlng. or Ьу апу !nfопnаtiоп storage or
retr1eval system. without the pГior wr1tten permlSs!on of the copyrlght owner and the pubUsher.
Thademarked naтes тау арреаг !n thls book. Rather than use а trademark эутЬоl wlth every occu-
rrence of а trademarked пате. we иэе the патеэ Оn1у !n ап ed!toГial fash!on and to tbe beneflt of the
trademark оwnег, w1th по lntentlon of lnfrlngement о! the trademark.
Russlап language edltlon 18 pub1lshed byWlll1am8 Publlshlng Ноиэе accordmg to the Agreement with
R&l EnterpГises Intematlonal. Copyrlght © 2007.

ISBN 5-8459·1124-9 (рус.) © Издательский дом "Вильямс· . 2007


ISBN 1-59-059419-3 (англ.) © Ьу Andrew Тroelsen, 2005
--------------------------------------------------------------- ~

Оглавление

Часть J. Общи.е 0ведеНИR о языке С# и. платформе .NET 41


Гnaвa 1. Философия .НЕТ 4З
rnss8 2. ТеХИОЛОГ.14JI СО3Дани« приnожеиий на языке С# 79

Част!. Н. Я~ЫК программироваlilИR С# 113


Глава 3. Основы языка с# 115
Глава 4. Язык С# 2.0 и объеКТНО-QриеtПИpое8JoIНЬ!Й ПОЯХОА 203
Гnава 5. Цикn сущеатвованИII объеХТ08 249
r,naliia' 6. CrрУКтУ,рированнаА обрабоtta искmoчений 271
Гnава 7. ИJt,.ерфеiiiС~ и Коn.riеlЩ)ll:И 299
Гnава 8. Интерфейсы обратного sы0вз •• делегаты и соБЫТИЯ ЗЗ9
Глава 9. Специanькые приемы' построения nmОВ 371
Гnава , О. ОбобщенМfI 41~

Часть ш. Лрогра,ммирование комnоновочныхбnокоа .NEТ 441


Гnава 11. КоМПОНQВОЧНlWе бnОQl .NEТ 443
Гnава 12. О'rображение типов) динамическое СВЯЗЬJВэние
и, программироввние с помощью атрибутов 495
rnaвa 13. Процессы, домены приnожений, :контексты и )(OC~ CLR 537
ГnВ8~ 14, Соэданме, мtfогопоточных приложенltЙ 565
fnaвi 15. CIL и роль Динамических компоновочных 6110КОВ 599

Часть 'У. Программирование с ПОМОЩЬЮ библиотек .NET 645


tлава 16. Пространство имен System.IO 647
Гnава 17. СерИ8ПИЗIЦИ8 объектов 077
rnaBa 18. Y'дa!leН'Hoe В;1аИМОД~ЙСtви.е .NEТ 701
Гnава 19. Создаимеокон с помощыо Sys~em.,Windows..Forms 751
Гnава 20. Визуализация графичесхих данных средmами GDI+ 80З
rлава 2'1. Использование элементов Yl1равnеltия Windows Forms 859
Гмва 22. доступ к базам данных о nомощыо АDО.НЕТ 929
Часть У. WеЬ~прило:жения и web-сервисы XML 1007
Гnава 23. WеЬ..страницы и WеЬ·эnементы управлеlЩА ДSP.HEТ 2.0 1009
Гnaв.a 24.Web-ПРИЛОJCения ASP.NEТ 2.0 1081
Гnааа 25. Web-серви.сы XМL 1117
Предметный укаЗ'атеnь 1161
Содержание

Об авторе 30

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

Введение 31
Вы и я - одна команда 32
Обзор содержимото .книги 32
Часть 1. Общие сведения о языке С# и платформе .NEТ 33
Часть П. Язык программирования С# 33
Часть т. Протраммирование компоновочных блоков .NEТ 35
Часть IV. Протраммирование с помощью библиотек .NEТ 36
Часть У. WеЬ-приложешm и Web-сервисы XМL 38
Исходный код примеров книги 39
От издательства 40

Часть 1. Общие сведения о языке С# и платформе .NET 41


Глава 1. Философия .NET 43
ПреДыдУЩее состояние дел 43
Подход C/Win32 АР! 44
Подход С++ /MFC 44
Подход Уииal Basic 6.0 44
Подход Java/J2EE 45
Подход СОМ 45
Подход Windows DNA 46
Решение.NEТ 47
Отавные компоненты платформы .NEТ (CLR. CТS и CLS) 48
Роль библиотек базовых классов 48
Роль языка С# 49
Другие языки программирования с поддержкой .NEТ 50
Жизнь в многоязычном окружении 51
Компоновочные блоки .NEТ 52
ОДНОМОд.Ульные и МНОГОМОд.Ульные компоновочные блоки 54
Роль CIL 54
Преимущества C1L 56
Преобразование СIL-кода в набор ШlстрУКЦИЙ, соответствующих платформе 57
Роль метаданных типов .NEТ 57
Роль манифеста компоновочного блока 58
Общая система типов 59
тип класса 59
тип структуры 60
ТИП интерфейса 61
ТИп перечня 61
СодерJk'Эн.ие 7
ТIш дe.ttе!"ата: 62
Члены типов 62
BcтpoeJIНЫc 7иIIы данных cтs 62
ОрщеЯ"зъnювые спецификации 63
ThрЩlТ~ CLS-совмес:тимOQТИ 65
Qбщеязьшовая среда вьшолвени,н 65
РaзJtи<niя: МеЖДУ компоновоЧ}fblМИ б:IЮКaмJ1. ЦРОСТРЩlстваю-I имен и тиnвм:u 66
прcwpaммный доступ :к пространствам им.en 70
Сс:ылки на ВНenIШ1е :комuоиово...ные бло:ки 72
ИсIIОЛЬЗОВ8Щ'fе i1da8Дl.~e "72
Просмотр ClL-кода 73
Просмотр метаданных 'I'ИIIОВ '74
Просмо'I'p меrгэдam:tЫХRОМnОНОВОЧ1iЫX блоков 74
Инсталляция среды ВЪ1Полиеншt.NEТ 75
rIлатформещщя ~езавиcmvIOОть.NEТ 75
Резюме 77

Глава 2. ТеХНО110rмя создаН"1 цриложени" на языке С# 79


Уетае:ов:ка .NEТ Framework 2.0 SDK 79
1(омцидятор ~О:rd<ХНДШ;>ЙСТРЩЩ для С# (С5с.ехе) ВО
l']астроiШa :К(j)!"mИЩIТQра ко:мавдной: <:ТрOltИ Д1IЯ С# 81
Дополнительные cpeдcrвa командной f:;ТРОКИ; .NET 82
КоМIfОliOВК~ С#-npиложений С по'М"ощъю СБС.ехе 82
cqылkи на внeпnmй комnонdвочный бло:к 84
I:\oмnилнцщr мнржества файлов 85
Сс:ыщщ на мыояtество Б;frеп:lН:!'IX -кеьrпoновочных блоков 86
Работа с ответНhIМИ фaйJxцми С$С.ехе 86
Ответный фrol.n. используемый ПО умолчанцю (csc.J·spJB7
От.падчи:н: RОмандНаП стро:ки (cordbg.exe) 87
Отладка с щщандной стрmш 88
Н:омnoновка . NET-приложен:иЙ с 1;rc)МQщъю~d 89
Активизация nвeтовой схе.мы С# 89
Настройка фильтра файЛОl\ t .CS 90
ПОДIfЛючеЮfе csc.ex:e 91
Ассоцдация команд с nyн:ктами мБНЮ 92
ИСПОJ~Ование фрar.ментов праграммного кода С# 93
КоМnОlЮВI(З. . NЕТ~ПРИJЮжеВИЙ с 1JОМ.ощью Sh!ПJJDeve1ор 94
ВОЭМОORности ShщpDevdор 95
Окна проекrов и кдассов 95
Обзор 1ЮМПО1-IОВОЧНЬЖ бло:ков 97
Инструменты проектирования Windows FbtrDS 97
КоI\IШОНО1Ща .тт -при.ТJОЖ!lliИЙ С помощью V1sua1 С# 2.000. Express 99
Компоновка .NEТ·nPИЛQЖенИЙ с помощьщ УШи.а! Stuwo 2005 10О
ВОЗМQжваст.и Vi8Ua} Studio 2005 100
УтиJIИта обзора решений: на
Утилита обзора классОв 102
8 Содержание.

ОюlO определений программного кода 103


Утилита обзора объектов 103
Интегрированная поддержка факторизации npограммного :кода 103
Фрагменты программного кода и окружения 106
Средства визуального проектирования классов 106
Стенд тестирования объектов (ОТВ-тестер) 109
Интегрированная справочная система 110
Дополнительные средства разработки .NEГ- приложений 111
Резюме 112

Часть 11. Язык программирования С# 113


Глава З. ОСНОВЫ языка С# 115
Структура ПРОСТОЙ про граммы на С# 115
Вариanии метода МainО 116
Обработка аргументов командной строки 117
Использование аргументов командной строки в Visual Studio 2005 118
Несколько слов о классе Sуstеm . Епviroпmепt 119
Определение классов и создание объектов 120
Роль :конструкторов 121
Утечка памяти 123
Определение Мобъекта приложения" l23
Класс System.Console 124
Ввод и вывод в KТlacce Console 125
Форматирование консольного вывода 126
Флаги форматирования строк .NEТ 127
Доступность членов 128
Доступность типов 130
Значения, назначаемые переменным по умолчанию 131
Значения. назначаемые по умолчанию, и локальные переменные 131
Синтаксис ИНИЦИали3anии членов -переменных 132
Определение констант 133
Ссылки на :константы 134
Определение полей только для чтения 135
Статические поля только для чтения 136
Ключевое слово static 137
Статические методы 137
Статичес:кие данные 138
Статические конструкторы 140
Статические классы 141
Модификаторы naраметров методов 143
Способ передачи параметров. используемый по умолчанию 143
Модификатор out 144
Модификатор ref 145
МодифИRaтор рагaшs 146
Итерационные конструкции 146
СодержаttJ.1е 9
цикл fol' 147
ЦИШI lQ1:each 147
Roнстру!ЩИИ while и do/wblle 148
Конструкщ:rn выбора решен;ий 1:1 oцep~ срrщнeFIИЯ 146
Оnера:горLf/else 149
Оператор switch J 50
nПIЬ1 , .харакrеризуеМЫе значениями . и сСьшочные типы 151
ТШrы. характеризуемые значениями. СGI>IЛОЧНЬ1е типы и оператор
присв~ания 153
типы. характеризуеыы~ зn~ченnям:и и содержащие ссъшочные ТШIЫ 155
Лереда"'JЗ ССЫ.lIOЧЩdX типов ЩI ЭЩiЧeJlИЮ ] 57
Л~редача ссьщочных типов ПО ссылке 158
1'nПbI, характеризуемые значеюшм:и. и ССhIЛоч.н~е типы:
з.аключителЫlые эа..чечаниЯ ] 59
bтreр:ации ФЭ,ЦЯВИИ olJъe&rнoгo образа и воостановления: itЗ объeкtноro lJбpaзa 160
I1pЩidеры СQЗДания объeR'I'НЫX обраЭ()1П't восстано:вления значений 161
Восстановление из объ~т~оrо образа для I:10ЛЬ30:вател:ьских 'J'ИШ)В 163
Р-абcтrа. с переЧЮIМИ .NEТ 1.64
Базовый класс System.Enum 166
Мастер-:класс; .system.ObJect 168
Поведение System.Object. задainJое nь УМШР:IЭНИЮ 170
Переопределение элеме}JТOВ System.0l!Ject, эfiДанных nOУМОЛЧанию 172
Переonределение System.Objecf;lbString{} 172
П~реопреде;.iIeние System.Object.Equa1s() J 73
Переопределение Systеm.ОЬJеоt.GеtНазhСОdеО 174
ТестироВafШС nepеопределеыных членов 175
Ста:тичеCJ:Шe ЧllеНЫ S}'stem.Object 176
ТИцы ДШЩЬ1Х S~SteШ (и щ': Об:оз:н~чен.ия в СИ) 176
Экonери:менты с ч:исло.вы:м:иТ:ЮIa~ данных 179
Члены Sуstеm'вооlеап l~P
Члены System:Cha:r 180
Анализ значений СТРО1{()вык:дайпЬJ:Х 181
Эystem , Date1llne и SУБtem.ТlmеSрan ИН
тиц да:шц.IХ Syst;em.SЦing 182
Базовые операщщ со CtpOE-aIIЩ 183
Уtrpa1J:/Iлющие последова:reл:ыюсти 184
БукваЛЫlОе восnpоизве:дени::е СТРО}( в С# 185
Роль System.Thxt.StnngВui1'deJ' 186
'limы массивов .NET 187
Мас~ивы в :начестве параметрРВ СИ ВО8вращаеМЫХ8наченийJ 188
Работа с мнaroмерными массивами 189
Базовый масс System.Array 191
1Ии:ъt G раэреII1ение.~ npинимать значение ПШI 192
Рабо:ra с типами~ ДЛЯ которых ДОПУС.ТИМы зiiачения nulI 193
Операция ?? 194-
Пол:ыювательсние простращ:';Гва Ю4ен 195
АБСОlIЮТные имеда типов 196
1О Содержание

Использование псевдонимов 198


Вложенные пространства имен 199
Пространство имен по умолчamпo в V1sual Studio 2005 200
Резюме 201

Глава 4. язык С# 2.0 и объектно-ориентированный подход 203


тип масса в С# 203
Перегрузка методов 206
Использование this для возвратных ссьток в С# 207
Определение открытого интерфейса масса 209
Принципы объеRТно-ориентированного программирования 210
Инкапсуляция 210
Наследование 211
Полиморфизм 212
Первый прmщип: сервис инкапсуляции С# 213
Инкапсуляция на основе методов чтения и модификации 215
Инкапсулнцин на основе свойств класса 215
Внутреннее представление свойств в С# 218
Контекст операторов get и set для свойств 220
Свойства. доступные только для чтения, и свойства,
доступные только для записи 220
Статические свойства 221
Второй принпип: поддержка наследования в С# 222
Управление созданием базовых ,классов с помощью base 224
Множественные базовые классы 225
Хранение семейных тайн: ключевое слово protected 225
Запрет наследования: изолированные юшссы 226
Модель локализации! делегирования 228
Вложенные определения типов 229
Третий принцип: поддержка полиморфизма в С# 231
Ключевые слова virtual и оveпidе 232
Снова о ключевом слове sealed 233
Абстрактные юraссы 234
Принудительный полиморфизм: абстрактные методы 234
Возможность скрывать члены 238
правила приведенин типов в С# 240
Распоанаваниетипов 242
Приведение числовых типов 243
Парциальные типы С# 243
Документирование исходного кода в С# с ПОМОIЦЪю XМL 245
символы форматирования в ХМL-коде комментариев 247
Трансформация ХМL-кода комментариев 248
Резюме 248

Глава 5. Цикл существования объеkТОВ 249


Классы, объеRТЫ и ссьmки 249
Содержание 11
Оtиовные ~ёдения о существовании объектов 250
CТIrHQД дп:и .new 251
Ролр :&орlЮЙ при~щ:tJi:е~ 253
Th.tlершum о.бъектов 255
тип Systern.GC 256
АктИвизация сборки муоора 2'57
Создан:и~ оQъектов. прецvсматривающих фnнanи:зацию 260
Переопределение System. ОЬjесf.FtщЦ~еО 261
Детади процеr:са финализации 263
Создание объектов, прfЩYCматривaIOЩИХ освООоЩll.ение ресурсов 263
Снова о :кЛЮчевом слове using 11 С# 265
Создание типов, ~матривающих acвoбwtщeниe·ресурсов·u фИН3.J1изацию 266
ФОРJlo(aJIИэоващlЫЙ шаб.щН;f ОСВЩ)Qждеmm ресурсов 267
P~Me 269

Глава 6. Структурированная обра6отка МСКJ1lОчений 271


Ода, оnщбкам. и Щ:КJIЮЧeнmrм 271
Роль обрабо'ПW ис:кдюч~ний в .NEТ 272
Атомы обраоотI<И ИС}tJIЮче'f:I.ИЙ Ii .NEТ 273
Базовый класс Sygtern.Ex()eption 274
Проетeйnшй пример 275
~нерирование исЮI10чеНйЙ 277
Обработка исключени,й 278
Конфигурациn состoromя ИСIfJIIОЧений 280
Свойство ThrgetSite 280
Свойство S1ack'n-ace 281
СВОЙСТВО НеlрLJnk 282
СВQЙСТВЭ Оаи 283
Исrщючения сиc:reмn0I'о уровня (Sуstern:SysteщEхсерtiqri) 284
ИСКIJЮченияуроВИJi приложевllЯ (System.Application&oeption) 285
СОЗДiUiИе пользовательских ИCЮIючеЮlЙ. раз... ~$5
Создание полъзователъски:х иCКJlючemrit два... 287
СClЭ:цamre По.1IЬ3Oвателъских .исклюЧ'ениИ~ три! 287
Обработка Ml-IO!ЖfilСТВ исItШQЧeниif 288'
Qбщие одераторы catcb 2~1
Thнерирование вторичных ЙCI<J.IюченИЙ 291
ВНУТР~llшеискmючеиия 29~
В1шн Ш1aIly 293
Что ~ ч;ем I'енер.цруется: 294
ИCIЩЮчеаия. оетавдЩ.еся без обрарOТJЩ 29J:}
Отладнанеобработанных ИСЮIючений в Visual stшflо 2005. 298
Резюме 296

rna~a 7. Интерфе_йсы и ~оллеJЩИИ 299


Опреде.i-rс.tШе Иlперфейсов вС# 299
РеЗJIR3ЗЦИЯ интерфейсов в Cft 300
12 Содержание

Интерфейсы в сравнении с абстрактными базовыми классами 302


Вызов членов интерфейса на уровне объекта 303
Получение интерфейсных ссьшок: ключевое слово as 304
Получение интерфейсных ссылок: ключевое слово is 304
Интерфейсы в качестве параметров 305
Интерфейсы в качестве возвращаемых значений 307
Массивы интерфейсных типов 308
Явная реализация интерфейса 308
Разрешение конфликтов имен 311
Построение иерархии интерфейсов 312
Интерфейсы с множеством базовых интерфейсов 313
Реализация интерфейсов вVisua1 Studio 2005 314
Создание перечислимых типов (IEnumerable и lEnumerator) 315
Методы итератора в С# 318
Создание клонируемых объектов (ICloneable) 319
Пример клонирования 321
Создание сравнимых объектов (lComparable) 324
Сортировка по н/!,бору критериев (IComparer) 327
ТИпы. определяющие сортировку. и пользовательские свойства 328
Интерфейсы из пространства имен System.Collections 329
Интерфейс ICollection 330
ИнтерфейсIDictionary 330
Интерфейс IDictionaryEnumerator 331
Интерфейс IList 331
Классы из пространства имен System.Collections 332
Работа с типом ArrayList 333
Работа с типом Queue 334
Работа с типом Stack 335
Пространство имен System.Collections.Specialized 336
Резюме 337

Глава 8. Интерфейсы обратного вызова, делегаты и события ЗЗ9


Интерфейсы обратного вызова 339
ТИпа делегата .NEТ 343
определение делегата в С# 344
Базовые классы System.MulticastDelegate и System.Delegate 347
простейший пример делегата 348
Исследование объекта делегата 350
Модификация типа Саг с учетом делегатов 351
Реализация групповых вызовов 354
Более совершенный пример делегата 356
Делегаты в качестве параметров 357
Анализ программного кода делегирования 360
I<'овариантность делегатов 361
События в С# 363
Thyбинный механизм событий 365
Содержание 13
Прием достynающих событий 366
Упрощt:НН:ал регистраци;я событий в Visua1 Эщто 2005 961
"Разбо.р'tивые~ соБЫТИЯ 368
Анонимные методы в С# 370
Дocтyn- H "вн~IПНИМ· перем:енnым: 372
tpyпnовое r.q>eобра.зоввюre методав 11 С# 373
Реэюме374

Глава 9. Специальные приемы лостроеНИR ПЩОВ 371


Со:щWЦ[~ пользова'IJeЛЬCkИX индексаторов 377
Вари~ индексатора для ТИПа Garage 379
1Знy:rреnн_ее представлеНИе -индексаторов типов 380
3ашпоЧИТeлbliЫе замечания об ИНДекс;::аторах 381
Перerpyз:ка anер8ЦИЙ 382
Переrpузка бзщаpJlых оrn:рaщIЙ 383
операции += и -+ 384
Переrpузка унарных операций 384
Пере:грузкЭ. операций npоверки па тождествеНRОСтЬ 38-5
перqpуз;!щ операций cpabh-eRИ'.Я з86
Внутреннее представление перегруженных операций 387
ИСIЮЛЬ30ва1iие перетружеIo-Iык оперЩ1;ИЙ "~3iЫIШX, не Подцержи::ва.ющих
ш:рerpуЩ операций 389
3<Щ1IlOчителъ'НЫе эамечанил о переt"pузке оперanий 399
ПW1Ъэовательские преобр<!.ЗОвa.ниs:t типов 391
Преобра:юв!ШИ)! чиоел ЗЮ
Преобраэования т}тов Rдacca 391
СоздаНИе поЛЬЗовательских ПQДПРorpамм npеобразов_aнmr 392
Варианты mшого npеобрззования ДЛЯ типа $quare 394
Определение подпрограмм: -Неявного преобразования 395
ВнутреШIeе предст<uщение по.льзоватещ.с~ Ц0дrW0тpa.мм преобраэавания 396
Ключе:выtJ слова. С#. npедназначе:нные для более СЛОЖИЫХRоастру-нций 397
Rлючевое слово checked 397
Ключевое слово unchecked 400
Рабо'Щ с 'f.ипамиуказателя 401
Ключевое слово эizео! 408
Директивы црenpоцессора С# 409
Разделы программноro ROда 409
Условная КОМURiIЯЦИЯ 41 О
Резюме 412

Гnава 10. Обобщения 413


CHO!Ia О создани:и объеRтиых образов, восстановлении аRaчений
~ System.O~ect 413
Проt)лемы создания объeщ'JJЫX обршюв и :восстанавлбния значений 415
1'щtовЩ1 беэOIЩСНОСТЬ и строго Т'шц!эованные -коллекции 416
Проблемы создают объектш.rx образов и строго ТИIдiЗованНые нолленtI;ИИ 418
14 Содержание

Пространство имен System.Col1ections.Generic 420


'гип List<Т> 421
Создание обобщенных методов 424
пропуск параметров типа 425
Создание обобщенных структур (и классов) 426
Ключевое слово default в обобщенном программном коде 427
Создание пользовательских обобщеЮiЫХ коллекций 429
Установка ограничений для параметров типа С помощью where 430
Отсутствие подцержки ограничений при использовании операций 433
Создание обобщенных базовых классов 434
Создание обобщенных интерфейсов 435
Создание обобщенных делегатов 437
Имитация обобщеЮIЫX делегатов в .NEТ 1 .1 438
Несколь:ко слов о вложенных делerатах 439
Резюме 439

Часть 111. Программирование компоновочных блоков .НЕТ 441


Глава 11. Компоновочные блоки .NEТ 443
Роль компоновочных блоков .NEТ 443
РаСlIIИpенные возможности многократного использования
программного Iiода 443
Установка четких границ типов 444
Управление версиями 444
Самоописание 445
Средства конфигурации 445
Формат компоновочного блока .NEТ 446
Заголовок Win32 446
Заголовок CLR 446
пporpaммный код CIL. метаданные типа и манифест компоновочного блока 448
Необязательные ресурсы компоновочного блока 449
Одномодульные и МНОГОМОдУльные компоновочные блоки 449
Создание и использование одномодульных компоновочных блоков 451
Анализ манифеста 454
Анализ СIL-кода 456
Анализ метаданных типов 457
СОЗДaI-ше приложения-клиента в С# 457
Создание приложения-клиента в Visua1 Basic .NEТ 459
Межъязыковое перекрестное наследовюше 460
Создание и использование многомодУЛЬНЫХ компоновочных блоков 461
Анализ файла ufo.netmodule 462
Анализ файла airvehicles.dll 463
Использование многомодульного компоновочного блока 463
Приватные компоновочные блоки 464
Идентификация приватных КОМПОНОВОЧНЫХ блоков 465
Процесс зондирования 465
СIJ;церж.ание 15
Ко.нфюурация npиваТJ:1,ЫХ; JЩМДЩRJВОЧНЫХ блохов 466
Файлы ко.нфиrypацци и Vi~ua1 stшliо ~005 468
Утилита конфиrypa.щtИ .NEТ Framewotk2.0 469'
ощщед-осryn:нью :кйМ1JOНОв6чНЫе блоки 471
Строгая форМа имени 4:11
Создщmе C'.rpororp ~еЮ! ДJlЯCarLihrary.di1 473
Назначение строгого имеНPt в Viэual Shld10 2005 474
Установка и удаление общедостy:mtIiIX компоновочных бл'оков 4-75
Отложенная поДIIИСЪ 476
ИсПользование общедоступных :комIIонI!).зочиых бдоков 477
Л:l:щл:из ~щmфеста SharedCaI'UbClient 480
Кщrфиrypация общедос~ компоново~ блоков 480
ФЙКСgция версии общедоступного fЮМnОНОВОЧНОГО блока 481
Соэдание общtщоc-ryпноro RОМnОНQВ,ОЧ,НОГО блщш версии 2.0.0.0 481
ДIirnаШJЧескан привязttа R концретной версии ROъmоновоЧI;IОГО блоlШ 483
Снова об утилите 1Юнфиrypации .NEТ Framework 2.0 484-
.4iнализ внутреЩi;ei':i структуры GAC 485
Файлы пОлитики nyб.mщации щ>мдоновочныJt блспюв 487
Игнорирование. фЗЙJIа nолиLИКИ nyБJЩRaI:(Щi 488
$Jлемент <cod,e Base> 489
Пространство tJМ6Н System.CmШguгаtiCiП 491
Файл конфигурации M~ 492
Общая схема связей :КОМПОНОВОЧНЫХ блоков 493
Резюме 494

Глава 12. Отображение типов, динамическое связывание


'и программирование с поМощtalQ атрибутов 495
Метаданные 'типов 496
Анали~ метаданных перечня. EngJnеstэ.tе 497
Анщrцв метэдamIых ТЩ;Щ СМ 497
Анализ "!ypeRef 499
ПреЦСТaвJJеtmе метадашrыx КОJIЩОFIOВОЧ:ВОГО (Щока 499
Предст-авление ССЫЛОК на дрyrие КО1lof1]ОНОВОЧНВJе б.nоки; 499
Пр~дС"Гавлeюre строковых литералов 500
Отображение ТЩJов в .Nl!.l 50 1
.l<.дщс S%tem.1Jrpe 501
Получеtше 1)тре с ПОМОЩЬЮ Systеm.ОЬjечt.Gef.rypеО 502
Получение JYPe с помощью s~tещ.1:уре.Gеt1YPе(J 503
Получение Туре с помощьюtypеоfD 503
СD::щавИе riШ1ЬЗQВателъClЮГО npиложеmm ~ nPОСМ0Тра метf1данfiых 504
ОтображеЩfе методов 504
Отображение полей и с.воЙС-r.,в 504
ОтоБРaзlс€ние ре<wиаоваlIНЫХ ИБтерфеjiссJВ 505
Отображение вcnомогаl'ел:ЬНОЙ Щlформащщ 505
Реализация МainО 506
ОтображеЮfе па.раметров и возврauщемых ЗНачений метоДОВ 507
16 Содержание

ДИнамически загружаемые компоновочные блоки 509


Отображение общедоступных компоновочных блоков 511
ДинамичеС1(ое связывание 513
Класс System.Activator 513
Вызов методов без параметров 514
Вызов методов с параметрами 515
Программирование с помощью атрибутов 516
Потребители атрибутов 517
Применение встроенных атрибутов С# 517
Параметры конструктора для атрибутов 519
Атрибут Obsolete в действии 520
Со:кращешюе представление атрибутов в С# 520
Создание пользовательских атрибутов 521
Применение пользовательс:ких атрибутов 521
Ограничение использования атрибута 522
Атрибуты уровня компоновот.mого блока (и уровня модуля) 524
Файл Assemblylnfo.cs в Visual Studio 2005 524
Отображение атрибутов при статическом связывании 525
Отображение атрибутов при динамическом связывании 526
Перспективы отображения, статического и дИнамического связывания
и пользовательских атрибутов 528
Создание расширяемого приложения 529
Создание CommonSnappable1Ypes.dll 529
Создание подключаемого компонента в С# 530
Создание подключаемого компонента в Vistlal Basic .NEТ 531
Создание расширяемого приложения Windows Forms 531
Резюме 535

Глава 13. Процессы, домены приложений, контексты и хосты CLR 537


Выполнение традпционных процессов Win32 537
Обзор потоков 538
Взаимодействие с процессами в рамках платформы .NEТ 540
Список ВЬПIолняемых процессов 542
Чтение данных конкретного процесса 54з
Список множества потоков процесс а 544
Информация о наборе модулей npоцесса 546
Начало и остановка процессов с помощью программных средств 547
Домены npи.ilОжеНИЙ .NEТ 549
Список доменов приложения процесса 550
Программное создание новых доменов приложения 552
Программная выгрузка доменов приложения 553
lPаницы н:онтекста объекта 555
Контекстно-независимые и контекстно-связавные типы 555
Опреде.пение kohtekctho-связанных объектов 557
Провер:ка I(онтекста объекта 557
Срде~ние 17
Еще .аеOROЛЬ:КО·· СЛQВ о процесqa:x., доменах .приложения и нонтмстах
559
Хоcтинr 06щ~.язьnwвОЙ среды .вышJIнепия: 560
Параллелыюе вьmoЛiiеюrе CLR 560
Зarрузка кониретной версии СIЖ 561
Доnoлни:rеЛЫIblе XdСТЫ C L R 5 6 3
Pe~Me 563

Глава 14. Соэдание МНОГОnОТОЧНblХ приложени" 565


вэa:m.roCВffiJЪ ПРОЦеССDВ, доменов 1IpиложеНиi%. контекстов и потоков 565
Проблема КОНRуренции и po.iIЬ синх;ронизации пото:ков 561
КратlШЙ обзор делегатов .NEТ 568
Асйн.х;роннав прирdда деJ;lеГ'dТОВ 570
Методы Беg1nIпvokеО и Endlnvok.eO 570'
Интерфейс System.IAsYl1cResult 571
Аcи:юs:pо.ННЫЙ вызов методов 571
Синхродиза:ция :вы;зывающего потрщз, 512
Роль делеrа::l'а AsyncCallback 574
Родь класса Лsync.Resu.It 575
Передача и получеШiе ПОЛЬЗ0ва1'елъсю~ данных СОС'rofJНИЯ 576
Прострaшrrвоимен Sy.s1em.ThIead1ng 577
кла.сс $уst~ .ТhrеаФДg .Thrеаd 578
Получен:ие Щ:lформации об· oт.цeJIhНOM ПОТОRе 579
Свойства Narne 58Q
Свойство PrtoIity 580
ПроГрамм.ное СQздание ВТОРИЧНЫХ ПDТОI(ОВ 581
Рабе'i'а с делега'Т'ОмТhrеаdstart 581
·P~l$oTa с дещ:гатом Pa;r:arneter1zed'ThreadStart 584
I1риорwreТElЫе и фщ:юв.ые ЦОТРЩ1 585
пробт:ма )(ою.-урелwоtCl доступа 586
·Синхронизация с помощью ключевого сло:ва: lock вС# 589
СИНХрОН:'И:'1iщ;ИЯ с помощью типа Sys.tem.'Тhreadiцg.Monitor 590
СIiНxpО.imзatJ;Ия с помо:iЦЬЮ типа $ystem.Тllreadrng.Interlocked 591
Си,н.х;рони<iЭЦИЯ с ПОМОЩЬЮ атрибута {Synchronizat1on], 593
Т1рограммирование с помощыр таймеров обратного Щ>I30ва, 593
Пул ПQ1:'ОIЮВ CLR 595
Резюме 597

Гnава 15. CIL и роль динамических компоновочных бnоков 599


Природа nРОI])aм.IO:fPОВaюrя
11 те}!)мицах: CIL 599
ДИрективы. атриб}'Ты и жщы операций CIL 600
Роль дирeItтив CIL 601
Po,rrъ атрЩ1Y1'QВ сп.. 601
PoJIЬ КОДОВ опс:рaцRЙ C:IL 601
Различия.между мнемоН'ИЮ)й ц Ж)домопер~ CIL 602-
Добавлеnие и извлечение данных: стеновая природа CIL 603
18 Содержание

Челночная технология разработки 604


РольMeTOI{ в программном коде ClL 607
Взаимодействие с CIL: модифИRация файла".11 608
Компиляция CIL-кОда с помощью ilasm.exe 609
Компиляция С!L-Rода с помощью SharpDevelop 610
Компиляция СIL-Rода с помощью ILШЕ# 611
Роль peverify.exe 611
ДИрективы и атрибyrы CIL 612
ССЫЛRИ на внешние Rомпоновочные БЛОRИ 612
Определение текущего компоновочного БЛОRa 612
Определение пространств имен 613
Определение типов масса 614
Определение и реализация интерфейсов 615
ОпределениестрYRТУР 616
Определение перечней 616
Компиляция файла CIL1YPes.il 616
Соответствие между типами библиотеRИ базовых l{Лассов .NEТ. С# и CIL 617
Определение членов типов в CIL 617
Определение полей данных 618
Определение конструкторов типов 619
определение свойств 619
Определение параметров членов 620
Анализ кодов операций CIL 621
Директива .maxstack 623
Объявление локальных переменных 624
Связывание параметров с локальными переменными 625
Скрытая ссылка tШв 625
Представление итерационных RОНСтрукций 626
Создание компоновочного блока .NEТ в CIL 627
Соэдание CILCars.dll 627
Создание CILCaгClient.exe 630
ДИНамичеСl{Ие компоновочные блоки 631
Исследование пространства имен System.Reflection.Emit 632
Роль System.RefiectiO'n.Emit.lWenerator 633
генерирование динамич.ескогО' компонО'вочного БЛОRa 634
генерирование КОМПОНОВОЧНО'ГО блока и наБО'ра модулей 637
Роль типаModuleBullder 638
генерирование типа HelloClass и принадлежащей ему
строковой переменной 639
генерирование конструкторов 639
генерирование метода HelloWorldO 640
Использование динамичесl{И сгенерированного компоновочного блока 641
Несколько слов о' System.CO'deDOM 642
Резюме 643
Содержание 19

Часть JV. Програ",мирование С помощью БМБnмоrек .NEТ 645


Глава 16. ПростраtfС.тво имен Syst~m.IO 647
АНаЛИЗ пространства имен Syst-e:m.IO 647
Типы Dire~tOl"y[LrJfa1 11 File(Info) 648
Абстрактв:ы;й 6азовьЩ кдасс FДе$ys'temInfо 649
Работа с типом DirectoryInfQ 650
Переченъ FtleAttrlbutes 651
Перечисление файло13 G ПОМОЩЬЮ DirectoryInfo 652
СQздromе ыqдкаталогав (: ПОМОЩЬЮ DirectoryInfo 653
Работа с типом Directory 654-
Рабо'ta с:тшroМ "пасса Ddvelnfo 655
Работас классом FileЫfo 65(':;
Метод F"llelnfo\CteftteO 657
M~I)Д File1nfo.OpenO 658
Meтoдь.r }<lleInfo;O~ReadO и Fi1eImfo.OpenWrlte() 65g.
Метод File1nfo.Open'IЦtO 660
Meтo)lbl FlleInfo.Create1bctQ и: FilеInfо.Арр!щd1&iО 660
Рабcrrа с nrnOM Fi1e 660
Новые члены F:lJe в .NEТ 2.0 661
Аt5стракгный ддасс Stream 662
РаБQта с F11eS1ream 664
Работа с StreaInWrtier .I'I StreamRead~r 665
Запись в текC'ТCffl1.IЙ файл 667
Чтение из тeKCТQ130ГO файла 667
НепосреДGтве:mюе со:щaшrе типовStreamWritеr (StreamReader 668
Работа с'ЩЛаМИ Stтi:цgWrtter и Str1пgRеаder 669
P-аБDта с B1naryWriter н БiшuуRе&dег 670
проrpаммный моmtгoРШIГ файлов 673
.Асщ-pq>онвыИфай..'Ювый B13pд -вывод 675
Резюме 676

Глава 17. СериализаЦИII объектов 677


ОСНОВЫ еери:ализации объеюrnв 677
РQЛЬ O~ графcm 679
Itoнфшурирощnше оБЪeRТЩJ для сt;p;иaдIiшщии 680
ОткрЫ1'QIе ПОЛЯ. прива:гцые поля и открытые С.БрЙетва 681
Выбор формата сериализaцI'I:И 681
Интерфейсы IFonnatter и IRemotlngFOnnatting 682
Выбор-формата и тоcrnoсть J'ШНШ 683
Сериалйзация об'Ье:к~'I'UВ с помо!Цыо BiЦ~Fonnatter 684
РекоНСТРУ1ЩИЯ объеКтов с ПОМОЩЬЮ ЩnвхуFbJ;"D1аttе. 685
Сер~ализацх1Ji объектов с IЮМОЩью SQарR)J"щаttet- 686
СериализаЦИR uбъектов t помощью XmlSeria1izer 687
14mтролъ tенерируeмьr;x XМL- данных 688
Сохранение 1Wллешщй оОъектов 689
20 Содержание

Настройка процесса сериализации 691


Более глубокий взгляд на сериaJШЗaциIO объектов 692
Настройка параметров сериaJШЗации с помощью ISerIalizable 693
Настройка параметров сериализации с помощью атрибутов 696
Поддержка версий сериaJШЗации объектов 697
Резюме 699

Глава 18. Удаленное взаимодействие .NEТ 701


Понятие удаленного взаимодействия .NEТ 701
Пространства имен удаленного взаимодействия .NEТ 702
Каркас удаленного взаимодействия. NEТ 704
Агенты и сообщения 704
Каналы 705
Снова о роли форматтера .NEТ 707
Общая картина 707
НеСIЮЛЬКО слов о расширении стандартных возможностей 708
ТерминыудаленноговзаимодеЙствия.NEТ 708
Варианты маршалинга для объектов: МВR и МВV 708
Варианты акгивизации для МВR-тиnа: wкo и ело 710
Варианты конфигурации WКО-типа:
синглеты и объекты одиночного вызова 712
Сводная характеристика МВR-объектов 712
Инсталляция приложения. использующего удаленное взаимодействие 713
Создание распределенного приложения 714
Создание общего компоновочного блока 715
Создание компоновочного блока сервера 715
Создание компоновочного блока ЮIИента 716
Тестирование приложения. использующего удаленное взаимодействие 718
тип ChannelServices 718
тип Remot1ngConfiguration 720
Снова о режиме активизации WКО-тиnов 722
YCTaнoBI<a. сервера на удаленной машине 722
Использование ТСР-каналов 723
Несколько слов о IрССhaпnеl 724
Фaйльr конфигурации удаленного взаимодействия 725
Создание файлов ·.config сервера 726
Создание файлов • .config клиента 727
Работа с МВV-объектами 728
Создание общего компоновочного блока 728
Создание компоновочного блока сервера 729
Создание компоновочного блока ЮIИента 730
Объекты. активизируемые ЮIИентом 732
Схема лизингового управления циклом существования САО-типов
и WКО-синглетов 735
Схема лизингового управления. используемая по умолчанию 735
Изменение параметров схемы лизингового управления 738
Содер.*<Iн~е 21
НаСТРОЙIШ парам(!тров лизинrа. на. стороне серве-ра 739
Настройка пара:;метpqв ли.зинга:на cropoнe клиеmа 739
Спонсоры лизинrа сервера (и ЩIиеща) 740
АльТ€.pJia'ГИВньre xocты Д1Jя УДЗJ"1енных объектов 741
Хостинг удаленн-юх объектов с помощью сервпса Windo~~ 742
ХОС'Т'ИI'П' удаленных QБЫНт.QВ С ПОМОЩЬЮ тв 746
АоИIOq)ОJfiюе удаленаое JJЗа1!Модействпе 748
Роль атрибута !On~Way] 749:
РеЗюМе 750

Глава 19. Создание окон с ПОМОЩЬЮ System.Windows.Forms 751


Обзор цространства ЩW:eJi Systenl.Windows.Fbrms 751
Работа с типами Windows FQ:rms 75з
СазданЙ'е· главного окна :вручную 753
ПрИНЦШl ражраничении обязанностей 755
Роль :класса Арр'цсаt,10П 755
Возможности :класса ApplicatiOn 7216
Делегат System.Eve-пtнandl~г 7§8·
~Анатомия~ формы 759
Фующиональные возможности класса Control 7~O
ИСПОЛЬЗQВание возможностеЙ класса Соntro] 763
Ответ па собьция: MouseMove 764
Регистрации щелчков кн~шок мьnпи 765
Ответ на собьrrия ЮI;з.виатуръ;r 766
ФунЕци:овальные возможности масса Fortn 767
Цикл существования 'rипа Fbгm 768
Создание W1ndOWS-llРИЛОЖе.н:ий в vtsш:u Stlldio 2005 770
Получение доступа lj: Уf;'J'а.:ре:БШИМ элементам упраВления 772-
Анализ npoe1cra Windows Fолщ; .в VI$ua} stш:I.iо 200'5 773
Обра:ботка собыrrий в режимеnpoеRТИРОвa.mщ 775
:класс Ptograro 776
Неоmюдимъте компоновочные блоЕИ 776
Работ~ !J М.епuStr1р и ContexfМenuSbip 776
ДОбавление элемента "R:xtbox в MenuStIip '779
Создание KOJITeRcTНЫX мещо 780
Лроneрка СОСТОЯНИя ЭJ.Iементов .меню 783
Работа 0 ЗtаtlisStriр 785
Создание СИС11еМЬ1 меню 786
НаСЧ'щша Statusstrtp 'иЗ6
Работа с типом Thner 789
БюnочеlIие отобршце:ния 790
Вывод llОДCЮlЗОК для выбранных элементов мещо 791
СОСТОlUiие roтов:ности 791
Работа с Tho1Эtrtp 7&J2
Работ~ С 'ЦJolStripCont:.alner 797
Соэдаиие мш- ПРИJЮ)f(ещщ 799
22 Содержание

Создание родительской формы 800


Создание дочерней формы 801
Соэдание дочерних окон 801
Резюме 802

Глава 20. Визуализация графических данных средствами GDI+ 80З


Обзор пространств имен GDI+ 803
Обзор пространства имен System,Drawing 804
Утилитарные типы System.Drawing 804
Тип Point(F} 806
Тип Rectangle(F} 807
Класс Region 807
Класс Graphlcs 808
Сеансы Paint 81 о
Обновление области клиента формы 811
Доступ к объекту Graphics вне обработчика Paint 812
Освобождение объекта Gгарщсs 814
СистемыкоординатGDI+ 815
Едиюща измере~mя, предлагаемая по умолчанию 816
Выбор альтернативной единицы измерения 817
Изменение начала координат 818
Определение цветовых значений 820
Класс ColorDialog 821
Манипулирование шрифтами 822
Работа с семействами шрифтов 822
Работа с гарнитурами и размерами шрифтов 824
Список установленных шрифтов 827
Класс FbntDialog 829
Обзор пространства имен System.Drawing.Drawing2D 830
Работа с типами Реп 830
Концы линий 833
Работа с типами Brush 835
Работа с HatchВrush 836
Работа с 'ThxtureBrush 837
Работа с LinearGradientвrush 839
Визуализация изображений 840
Попадание в заданную область и операции перетаскивания для PictureBox 842
Про верка попадания в область изображения 845
Проверка попадания в область , отличную от прямоугольной 848
Формат ресурсов .NEГ 850
Пространство имен System. Resources 851
Создание файла *.resx проrpаммными средствами 852
Создание файла" .resources 853
Добавление файла" .resources в компоновочный блок . NEТ 853
Работа с ResourceWriter 854
Генерирование ресурсов в Visual Studio 2005 855
СОДlфжаНltlе 23
ЧтеJ-ше ресурсов nрогрaммJ;I!ЫМИ среДC'rВa'МИ 857
Резюме 858

Глава 21. Использование элементов управления Windows Forms 859


Эле1l«еНThl упра:влеЮf,я. Wiщ:lI;JWS Fbrtns 8'59
ДобaW1ение элемеНТ-О8 упра:влеюш:в форму ВРУЧ1-IYЮ 860
тип Control,Contr{)lCollectlon 862
ДобавлеJШеалементов управ.ленил '13 форму в Vfsual St1.ldto 2005 863
Работа ~ базовыми эл~меflТами ynpа:иlie't:Wя 864
Элеме:~IТ l.:abel 865
ЭlIемеItГ TextВox 866
Элемент Маskеd'Ib.."tiЗох 869
Элемент Button 871
ЭлемIШ'r:ът CheckВox. RadlоВuftоп ~ GroUpBox 873
Элемент CheckedListВdx 877
9дeМf$T Listbox 879
Элемент СоmЬоБох 880
Порядок переходов по нажатию JЩЗВШJIИ табуляп:и.l1 881
Мастёр настройки переходов по табуJIJЩИИ в82
'Установна lЩОЩИ. выБИраемой ПО умолчанию "8&2
Рабма с щэугими эдементами yup<Щllения 883
ЭЛемент' MonthC;ilendar 883
Элемент 1bolТip 885
Элемент ThbConttol 886
Элемент ТraсkБш 888
Элемент Рапеl 891
Элементы UpDown 892
Элеменt ЕпоrProvidеr 895
Элемент 1teeView· 897
Элемент Wе.ЬБтаwsеrs 903
СfjЩЦ~е ЛОЛЪЗ0ва'I'елъС1:МК ,э.т.tсментов упра:в,П,eюm Window$ Ропns 904
Соа;цщще ~зЬбражениИ 906
Соэдание ПОЛЫlQвательекого интерфейса режима npое;ктирования 906
Реади..-"ffiЦИЯ CarControl 907
Оnре:делецие noilIЪЗ0Ва,телъскщ< (i;ООЫТИЙ 909
Опреде.neЮilе ПОЛЬ3Qвателl,СIЩX свойс;:тв 909
КОнтроль анимации 9] 1
Отображение назвю·tИя 911
Тестиpuвщrnетипа CarContJ;o1911
Создан:ие П03IрЭовательской формы дщI Са:!;'Сопtrol 912
ПространСТВD имен System. СоmроnепtМоdе] 914
Совершенс'ХВоваНИережИМа npое'КТ'ированил CarControl 915
Оцредroiенн. е выбираемых по умолчзнmо свойств и событи;й 916
Вмбор Jofз0брщкеFtшI для ПaRеТlИинструменro:в 917
Создaнnе польsоватeдьaJi.ИX диалоговых окон 919
Свойство DJa1ogResu1t 920
24 Содержание

Наследование форм 921


Динамическое позиционирование элементов управления Windows РЬrшs 924
Свойство Anchor 924
Свойство Dock 925
Табличное и потоковое размещение элементов 926
Резюме 928

Глава 22. Доступ к базам данных с помощью ADO.NET 929


Высокоуровневое определение ADO.NEТ 929
Две грани ADO . NEТ 930
Поставщики данных ADO.NEТ 931
Поставщики данных Мiсrоsоft 932
Поставщики данных других производителей 934
Дополнительные пространства имен ADO.NEТ 934
ТИПЫ System.Data 935
ИнтерфейсIDЬСоnnесtiоп 936
Интерфейс IDЬ1Гапsасtiоп 937
ИнтерфейсIDbCommand 937
Интерфейсы IDbDataParameter и IDataParameter 937
Интерфейсы IDbDataAdapter и IDataAdapter 938
Интерфейсы IDataReader и IDataRecord 939
Интерфейсы и абстрактные поставщики данных 940
Файлы конфmypации и гибкость приложений 941
Модель источника поставщика данных .NEТ 2.0 942
Зарегистрированные источники поставщиков данных 944
Рабочий пример источника поставщика данных 944
Элемент <connectionStrings> 947
Установка базы данных Cars 948
Соединение с базой данных в Visual Studio 2005 949
Связный уровень ADO . NEТ 951
Работа с объектами соединения 952
Работа с ConnectionStringBullder в .NEТ 2.0 954
Работа с объектами команд 955
Работа с объектами чтения данных 957
Получение множества наборов результатов с помощью
объектов чтения данных 959
Изменение содержимого таблиц с помощью объектов команд 959
Вставка новых записей 961
Удаление записей 962
Обновление записей 963
Работа с объектами параметризованных команд 963
Указание параметров с помощью типаDbParameter 964
Выполнение хранимых процедур с помощью DbCommand 965
Асинхронный доступ к данным в .NEТ 2.0 968
несвязный уровень ADO.NEТ 969
Роль DataSet 970
Содержание 25
Члены Dataset 971
Работц с DataColUДUJ 973
СОЗД81Ще Dat.aColumn 974
Раэреше}Ще автоnpирamения:.Dдft полci1 975
Добавлeшrе DataColttmn в DataTh.ble 9.75
Работа с DataRow 976
Сврйство DataRow.RowState 977
Pa(io1'a с DataThl:;Jle 978
Работа с DataThbleReader в .NEТ 2. О 960
с.охранение DataSet (и DataThble] в формате XМL 980
Привязка DataThbleE .инreрфеЙсу iIOльзователя 982
Програ:ммиое удаление "трок 984
Применеrцiефильтров и COPT:ЦPOB~ 985
Об!Ювление строк 987
Работа СТИIЮМ DataVieW 989
Раба.та с адаптерами данных 990
-$эnолнение DataSet с ПOМD1ЦЬю aд~pa ДаННЫХ 991
Q'ro5раже;ние 11М~}I баi,JЫ данных в Понятные имена 991
Обновле1Цlе базы данных с ПQ~ОЩЬ1О объекта адaлrера дa.в.ных ~9З
Устмовка свойства InsertConttnand 994-
'Y'CТa80BRa свойства UpdateCommaIld 994
Уctанов!Ш своЙСтва DеlёiеСоmtiJ.and 995
Thн.еwrРОI!ание SQL-RОМaRД с ПОМОЩЬЮ типов пострoиreля ка:манд 995
Объекты DataSet с множеством таблиц и об~ты Dаta.RiЩtiоп 998
l1аввгаци:оюn.re возможности для связанных 'fаблиц )000
-Возможности мастеров данных 1002
стрorотишlзованныe объекты DataSet 1004
A1IтомаТИ'letЕИ тенерируемый компон€ит данных 1005
Рещоме 1006

Часть УI WеЬ.. п'ри.nnжени~ и WеЬ .. сервисы XМL 1007


Гnава 23. Web-страницы и Web-зnеменtы управления ASP.NEТ 2.0 1009
Ponь Н1ТР НЮ9
Web-npиложенил :и Web-серверbl 1010
Работа с вйрТуал:ън:ыми к<ttaш.Jгами пs 1011
Сервер разрабоТ1СИ ASP.NET 2.0 1012
PмьHrM,L 1013
Струи;rура HTML-докумеИТft 1014
Разработка IfI'ML-Формы 1014
Соэдание пользовательского интерфейса:на базе НТМL 1015
Роль сцenариев 1:UJИmiТа 1017
n:PkJМep ~ценария клиента. 1018
K-ОFIТролъ допустимо!;ти :вВOдm4ЪPf д8.ЮiA1X 1019
Лода1:fа запроса формм (G. EТ и POSТJ lQJ9
Создание ~классическоЙ· АSI?-crрающы 1020
26 Содержание

Ответ на отправку POST 1021


Проблемы классической ТеХНОЛОГИИ ЛSР 1022
DIaвHыe upеимущества ASP.NEТ 1.Х 1023
IЛавные преимущества ASP.NEТ 2 .0 1024
Пространства имен ЛSР.NEТ 2.0 1024
Модель программного кода Web-страницы ЛSР.NEТ 1025
Модель ОДI-ЮМОдУЛЬНОЙ страницы 1026
Модель страницы с внешним КОДОМ поддержки 1032
Структура каталогов Web-узла ASP.NEТ 1036
Роль папки Вiп 1037
Роль папки App_Code 1038
Цикл компиляции страницы ЛSР.NEТ 2.0 1039
Цmш компиляции одномодУЛЬНЫХ страниц 1039
Цикл компиляции многомо.цульных страниц 1040
Цепочка наследования типа Page 1041
тип System.Web.UI.Page 1042
Взаимодействие с поступающим IfITp-запросом 1043
Получение статистики браузера 1044
Доступ к поступающим данным формы 1045
Свойство IsPostвack 1045
Взаимодействие с исходящим НТГР-ответом 1046
Генерирование НТМL-содержимого 1047
Перенаправлениепользователей 1048
Цикл существования Web-страницы ASP.NEТ 1048
Роль атрибута АutоEveпtW1геUр 1049
Событие Еrroг 1051
Природа Web-элементов ynpавления 1052
Обработка серверных событий 1053
Свойство AutoPostвack 1054
тип System.Web. Ш.Сопtгоl 1055
Список вложенных элементов управления 1055
Динамическое добавление (и удаление) элементов управления 1057
Основные члены типа System.Web.uI.WebControls.WebControl 1059
Категории Web-элементов управления ASP.NEТ 1059
Несколько слов о System.Web.UI.HtmlControls Ю60
Создание простого Web-узла ASP.NEТ 2.0 1061
Работа с шаблоном страниц Ю61
Определение страницы Default.aspx 1064
Создание страницы lпventоry 1066
Создание страницьI BuildCar 1071
Роль элементов управления. связанных с контролем ввода 1074
Элемент RequiredFieldVa1idator 1075
Элемент RegularExpressionVa1idator 1076
Элемент RangeValidator 1077
Элемент CompareValidator 1077
Созданц:е отчетов по проверкам 1078
Резюме 1079
СФДElржан~е 27'

Гnава 24. Web-ПРИnО)J(ен"я ASP.NEТ 2.0 1081


Проблема состоаниа 10~l
Те:хволоrии управления состоннием .ASP.NEТ ]083
РОЛЬ состоЯ1:lIiЩ преДСТaDJlений АЗР.NEТ 1084
Демонстрация ИСП(ЦJ:ьзgвания СОСТО.!lНЩ.l представлeшrn 1084
Добав:JIение полъзовате':/IЬСКИХ дан.ньш состощшя преД;СТЗJЩf;8,ИЙ 1087
Несколыю СЛОВ о , данных состояния элемеmОI1 1087
Роль фaiЩа ЩQЬ;:tl.авах Ю88
Посдедиий пюбatIЪ,ЩiI;Й шанс ДЛЯ обработки мсКЛючени-й 1'090
БаООВЬ!Й класс HttpApp1icafion 109@
Различия меащу приnожеRНем и севнсом 1091
Поддержка д8ННЪrX СОCIГотrия прил.ожеНИR 1092
Изменение данных сОстощшя приложения 1094
ОбрабOТ]tа эа.:верmеmm рабоТы Web-npиложеmш 1095
Кэт npилu:щещm 1095
Кэшnрование данных 1096
Изменение фааlIа • .а$РХ lО98
ОбрабОТШl- сеансовЫх давшlX 1101
Дошщнителъпы:е члены HttpSesSlonState. ] ]03
Дщшые oookie 1104
соэдание д~ сооИе 1105
Чтение поступающих данных coo}de 1107
Нас-:гройкз. Web-ПР1-ШОЖенил ASP:NEТ с ПОМОЩЬЮ Wt:b.conftg 1108
Разрешение траCCЙJ>OВ':КИ с помощью <trace> 1109
НастроiЩа B~oдa со66щemill об ОIIШб:ках с ПОМОЩЬЮ .;:custoroErrors> 1110
СохрэдeJniС :цан.н.ых ср!--'Тоядияс помощью <sessloiiStare> 1112
Утилита адмщmcтрированин ~a A.SP.NEТ 2.О 11i4
Наследование конфигурации 1115
Резюме lH6

Глава 25.Web-сервисы XML 1117


.Роль Web-(~ервисов xмt 11 :i7
ПреиМуЩества WеЪ-сервисов XМL 1118
ОпределеЮfе клиента W.eb-сервиса,хМL 1118
ДOм:rtOHeнт:ы Web~серви:са XМL 1119
Служба ро~с,fЩi Web-сервиса XМL 112()
Служба описания W~Ь·серщша XМL 1120
Тран<'IIОРТJ:lЫЙ протщ<ол 1121
Пространст.ва имен .NEТ д,1IЯ Web-серВПСQБ XМL 1121
Пространство имен Syste:m.Web.Services 1I22
СоаДaшIе Wеь-сервиса XМL вручную 1122,
Тест:ирова:н:ие Web-c~c!l XМL J:J помощью WebDev.WebServer.e:x;e 1123
ТеСТRIpовщmе Web-серицса, XМL с РОМ;ОЩЬЮ IIS 1124
ПРОСМGТР WSDL-докумен'I'э, 1125
Ав1'аматичесЮf Г!tнер:ируемая страница 'ТеСТИРОВaIЩfl 1125
СОЗ,дaFIИе 'пользовательской стр.анlЩЫ теetrиpованю~ 1125
28 Содержание

Создание Web-сервиса XМL в Visual Studio 2005 1126


Реализация Web-метода ThllFbrtuneO 1128
Роль базового класса WebSeтvice 1129
Атрибут [WebSeтvice) 1130
Namespace и Descnption
Свойства ]130
Свойство Name 1131
Атрибут [WebServiceBinding] 1132
Иrнoрирование проверки соответствия правилам ВР 1. 1 1132
Отмена проверки соответствия правилам ВР 1.1 1133
Атрибут [WebMethod) 1133
Описание Web-метода с помощью свойства Description 1133
Устранение конфЛИRТOв имен WSDL с помощью свойства MessageName 1134
поддержка данных состояния WеЬ-сервисов с помощью
свойства EnableSession 1135
Язык описания Web-сервисов (WSDL) 1137
Определение WSDL-документа 1138
Элемент <types> 1139
Элемент <message> 1140
Элемент <poIiТype> 1140
Элемент <binding> 1141
Элемент <service> 1142
Снова о !Ipотоколах связи Web-сервисов XМL 1142
Связь НТГР GEТ и НТГР POST 1143
СвязьSOАР 1144
Утилита командной строки wsdl.exe 1145
Преобраэование WSDL-кода в серверный программный код Web-сервиса 1146
Преобразование WSDL-кода в npограммный I<ОД агента для клиента 1147
программный код агента 1148
Конструктор. заданный по умолчанию 1]48
ПОДдержка синхронного вызова 1]49
ПОДдержка асинхронного вызова 1150
Создание приложения клиента 1]50
Thнерирование программного кода агента в VisuaJ Studio 2005 116]
Доступ к пользовательским типам Web-методов 1152
Доступ к массивам 1153
Доступ к структурам 1153
DataSet ADO.NEТ
Доступ к типам 1155
Клиент Windows Fbrms 1155
Представление типов на стороне клиента 1157
Стандарт поиска и взаимодействия (протокол UDDI) 1158
Взаимодействие с UDDI в VisuaJ Studio 2005 1158
Резюме 1159

Предметный указатель 1161


ПОСВНЩ;:L1() эту книгу моей матери. Мэри 'Гроелсен. Мама!
Благодарю тебя за ПQДЦерЖlo/В проmлОМ. настоящем и буцущем.
Ах. да! И опас.lfбо за ТО. чro 1'ЬJ не стала наказыва'ТЪ меня. ИО1;да Я,
прmпеJ1 ДОМОВ с "ирокезом".

Люблюmeбя.
Лух.
30 Об авторе

06 авторе
Эвдрю Троелсев (Andrew 1roelsen) носит титул МVP (Most Valuable ProfessJo-
nal- "самый ценный специалист") по Visual С# в Мicrоsоft. а также является
партнером. преподавателем и консультантом Intertech Тraining (http:/ / www .
IntertechTraining. сот). центра обучения разработчиков ,NEТ и J2EE. Он явля­
ется автором множества книг, среди которых Developer's Workshop to
and AТL СОМ
3.0 (Wordware Publishing. 2000). СОМ and .NEТ lпtеroреrаЬiШу (Apress. 2002). Visua1
Basic .NEТ aпd the .NEТ Plaiform: Аn Advanced Guide (Apress. 2001). а также книга
С# and the . NEТ Plaiform (Apress. 2003). которая была удостоена ряда специальных
наград. Кроме того . он является автором множества статей по вопросам .NEТ для
MSDN online и MacThch (В зтих статьях рассматриваются различные аспекты меж­
платформенной независимости .NEТ) и часто выступает с докладами. посвящен­
нЫМИ .NEТ, в конференциях и грушrах пользователей .
В настоящее время Эндрю Троелсен проживает в Миннеаполисе. шт. Миннесота.
со своей женой Амандой. В свободное время он мечтает о том. что Wild выиграют
Кубок Стэнли. Vikings въщграют Суперкубок (он бы хотел. чтобы это произошло до
его пенсии). а Тimberwolves станут многократными чемпионами NBA.

о научном редакторе
Гэвив Смит (Gavin Smyth) являегся профессионалом в области программного
обеспечения с многолетним (и. как он считает, слишком большим) опытом разра­
ботки программ - от драйверов различных устройств до приложениЙ. предназна­
ченных для многоузловых серверов на таких разных платформах. как "несгибае­
мые" операционные системы реального времени UnJx и Windows. и таких язьшах
программирования. как ассемблер. С++. Ada и С# (не считая множества других. не
менее достойных языков). Он выполнял заказы для таких компаний. как вт и Nortel.
а в настоящее время работает для Мiсrosоft . Thвин Смит имеет ряд собственных пе­
чатных работ, вьпnедш:их в научных издательствах (ЕХЕ и Wrox- где они сейчас?).
но в какой-то момент он пришел к заключению. что критика чужих публикаций ока­
зывается куда более плодотворной. Помимо этого. когда он не борется в своем саду с
сорняками и насекомыми. он пытается заставцть роботов LEGO делать то . что они.
по его мнен:ию. должны делать (зто все исключительно ради детей- честноl).

Благодарности
Выпуск третьего издания этой книги был бы просто невозможен без поддержки
и помощи многих окружающих меня людей. Во-первых, следует выразить благо ­
дарность всей команде издательства Apress. Каждый из ее ЧJJенов приложил не­
мало усилий. чтобы превратить мою "сырую' рукопись в безупречный np0дYIiT.
Далее, я должен выразить признательностъ моему научному редактору. Thвину
Смиту (известному также под псевдонимом Eagle Еуе - Орлиный IЛаз), который
вьшолнил огромную работу. чтобы уберечь меня от множества ошибок Все остав­
шиеся оnrn:бки (опечатки, неточности в программном коде и т.д.). которые смогли
"пробраться" в эту книгу. конечно же. лежат на моей совести.
Спасибо моим друзьям и членам моей семьи. которые (В очередной раз) терпели
мои цейтноты. а иногда и связанную с 'этим несдержанность в поведеНШi. Такой же
блarодарности заслуживают мои друзья и сотрудники из Intertech ТrainJng. Я очень
ценю оказанную вами поддержку (как прямую. так и косвенную) . Наконец. отдель­
но е спасибо и " все фантики" моей жене Мэнди за ее любовь и содействие.
ВведеН\1В 31

Введени'е

Я
менталрн~
ПOМfПО .цреАЩ, ~oгo лет ' тому J:1aЗЗД, котда я npeдлDЖИI1 ИЭД<'i-1'елъ.етву АргesБ
юпrry. посвященную' еще не выпущенному 11а тот момент пан~ту Щ:J:стру­

cpelXC'FB рааработки ПОД нз.эвзниеМ Next Generatlon WiDdows Servfices


[NGWS- cepBuq;r Windows с.ледYКIIЦего поколения). Вы, навеРlIое. зна~. что цз­
кет NGWS в }~онечном CtfeTe стал тeM~ что сеroдня :называется платформой ,NEТ.
ПараЛДeJlbl:fО с моими ПССЛf{ДОВа:ния:ми в области разрабonи языка прогрaммиpG­
вания С#. 'и rurатформы .NEТ:ш'.JIO [!оад.ание началъп.ого 1Jaрианта соответствующей
руноrmси.. Это бы,л фантастич.есRИЙпроект. но 11 должен IiриЗШ!.ТЬСЯ. что писать
о' т~ологlЩ'. 't'(:)roрая претерпевала весьма эm1ЧИтеЛЫlые изменения ~ ходе сво­
ей раэработ.ки,бъmо занятием, очень действyR)ЩИМ на нервы. Н. ечастью, Ц9СЛе
МJЮг.их. бессонных ночеИ. toдe-тo 1\ началу лета 2001 года. первое и~дание КFIИГИ С#
artd the .NEТ Plt1yotm было опуБJШRовано пОЧТй одновременно с выходом .N:EТ 1.0
Веtз2.
С того ~ремени я был чреавычaiiно рад и благодарен 'Тому. что ЭТа I<FЩГа- очень
благоск.ЩПiНО Пpй:FIИМaется прессой 'И' самое IЛaВНое, читатедnми. За эти годы KНU­
га пpeдлar~асъ в на честве S'оминанта на npемшо JoJt Award (л. To~a ~пролe'l'(Щ" ... )
и на премию Referenceware ЕХсеI1enсе .Award 2003 года s ilатегории кшrг по цро­
граммиРQва,нию(и я с-частпив, wro на этот раз мне повeзJIO),
BТOPQ~ ИзДЭlШе этой КJШrи (С# Ш1li the .NEТ Platjorm. SeCQnd ЕdШon) Дал!;) мде
возможность 'ВН'.JIЮЧИТЬ в нее Maтep1laJI, соответствующXdЙ версИИ 1, 1 платформы
.N;Eт. Хотя второе издани.е Illiиm содержало обсущдение :мно\Жества H€lBыx. ';ГеМ. ряд
тап и примеров .8ЮIЮчи'1'Ь в OI«)нчs.тМЬНЫЙвариaнr кнши все же не удадоер.
T~epъ. ROгда :книrа предt'тaliJ.rена в третьем издаюш, $I. с удо:вдетвОрe:щ<tем MOry
зая,вИТh, что она содержит (почти) все темы и nptwepbl, КОТQръщ-я н:е смог предста­
BJp'h lJ цpeды.uyщиx изДаниях, это издание не ТОJJЫФ учит~ает все i!rШого'Щ(Щен­
ные усовершеНствования, пре)(Лarnемые в .NEТ 2.0. но вюno~ет и ряд !'Щiil!. ЕОТО­
рые. буцучидавно написamIЫ.Мй, оставались до сих пор неопубдикоВ;ШНЫМИ- это
тmсается, наприм:ер, оnис.аБ:ин CIL (t:ommon Intennediate L.angu:age - 9БII(ИЙ про­
межуточный .fIзык•.
:Как и в предыдУЩИХ иВдаНИЯХ.lJ ЭТОМ. третьем иадании IGЩГИ FЩ ос;в:ове про­
стото И пошi:I'н.arо материала предетавлены .,нз:ьrк прогрlЦl4МИроБa:fЩН С# и библи­
отеки базовых &Ласroв .NEТ. Я шnwгда :не ПО!lИJ!,{ал СКJIо}Шо~ть HeКQT~ЫX авторов
Н, t.QЗДа.нию технических книг. более похожих на руководство по ПОДГО1.'Ощсе Е: ЗКГ
замену GRE. чем пригодный ДЛfI Ч'I'ения: теке!.: Задачей этоro нового дздания по­
иреж.вему осТается предоставление вам информации. необходимой ДJШ D.острoemш
прогр.а.ммных реше'ЮIЙ сегоДItя, а не расточительная трата BpeMe;mJ на рассмотре­
ние :мнЬжеЕ1'Ва. деталей. 1<оторые окаmuваются важпь:щи ДЛЯ ОЧe,JiЬ УЗROrd крута
спе.цИа:лИстов.
32 Введение

Вы и я - одна команда
Публикации разработчиков новых технологий предназначены для очень требо­
вательной аудитории (я должен знать это не понаслышке - ведь я один из них).
Построение программных решений дл1f. любой платформы требует чрезвычайной
детализации и учета множества особенностей соответствующей отрасли, I-tOмпа­
нии, .клиентской базы, а также учета сути дела. Вы можете работать в электрон­
ном издательстве, разрабатывать системы для федерального или местного пра­
вительства, работать в NASA или каком-то оборонном ведомстве. Я, например,
разрабатывал программное обеспечение для обучения детей, создавал различные
N -звеШfЫе системы и участвовал в многочисленных проектах для медицшlСКИХ и
финансовых учреждений. С вероятностью почти 100 процентов тот программный
код, который вы создаете на своем рабочем месте, не имеет никакой связи с про­
граммным кодом, который пишу я (если, конечно, нам случайно не приходилось
работать вместе).
Позтому в этой книге я сознательно избегаю примеров, в которых программный
код связан со спецификой определенных отраслей производства или сфер про­
граммирования. Я пытаюсь описать возможности С#, объектно-ориентированно­
го подхода, CLR и библиотек базовых классов .NET 2.0 с помощью примеров, не
использующих такой специфики. Вместо того чтобы в каждом примере заполнять
таблицы реальными данными, рассчитывать платежки или выполнять КaI(ие-то
другие специальные вычисления, я буду рассматривать объекты, с которыми могут
иметь дело все, - например, автомобили (с их геометрическими формами и слу­
жащими соответствующего предприяти1f.', добавленными для полноты картины).
И'ryТ на сцену должны выйти вы.
Моей целью является как можно более понятное объяснение возможностей яэы­
ка программирования С# и описание различных аспектов его применения в рам­
ках платформы .NEт. Я сделаю все, что будет в моих силах. чтобы вы, используя
знания и навыки, полученные в процессе работы над этой книгой, могли продол­
жить дальнейшее освоение соответствующих технологий.
Вашей целью является освоение этой информации и применение ее к вахпим
конкретным задачам программирования. Я, конечно, понимаю, что ваши проекты
вряд ли напрямую связаны с автомобилями, имеющими имена домашних любим­
цев, но так уж заведено в прикладных науках! Уверен, если вы поймете КОfЩепции
платформы .NEт. представленныe в этой книге, то сможете предложить и реализо­
вать решени1f., подходящие ДЛ1f. вашей конкретной среды программирования.

Обзор содержимого книги


Книга Язык npогра.м.мupованuя С# 2005 11 платформа.NEТ 2 .0, 3-е 113даНl1е де­
лится на пять логически обособленных разделов. каждый из которых состоит из
глав, тем или иным образом связанных между собой. Если вы имели возможность
оэнакомиться с одним из предыдущих изданий зтой книги, вы сможете заметить
некоторое сходство в названиях ряда глав, но знайте, что здесь почти на каждую
страницу был добавлен новый материал и дополнительные примеры. Вы можете'
также заметить, что некоторые темы, также освещенные в первом и втором изда-
Введение 33
ШU1X (нацример. сериал:изация объе~ro:в и сборЩ1Щ мусора .NEТ). ::щесъ представ­
лены в ~дe O'IДелъных IШm.
Кроме 'ГОго. и ВhI вправе это оЖЩta.:n.. третье издание ~IИГИ содержит :несколько
глав е совершенно H08ым материалQМ (В Ч~СТRОСТИ главу.. посвюценную сиН.тaJ~СИ­
су И семан:rике CIL) и noдробвоеОDИсaщrе опецифичес:ких ВО3МОЖlЮСТей .NEТ2.0.
Теперь. после всех ~делаиНых ОГDВарСщ. мы перейдем:к .IqJа.rn<ОЙ .харантериCТИitе со­
держимоro R1JИI'И по <.!астям И rnавам.

Часть 1. О.бщие сведения о языке С# и платформе .NEТ


Целью ЭТОЙ части IQIИГИ Шlляется описание баз(щЦIX npпнцилов фуmщиони­
рования платформы .тт, системы Т}ЦlOВ .NБТ И раз.n:ичиых инструыеitТaJlliНЫХ.
средств разрабопm.. используемых при СОЗДании ПРИJl0Жециif .NE"Г (многие из Ta~
кик иаструмеНТaJIЬНЫХ средств ЯВJШЮ1'СЯ lIРorpам;мн:ьrми продуктами с QТttрытым
исходным «адом). 3десь же npедстmшеНЪ1 базовые ВОЭ:МОЖН0СТff языка npограмми­
роlЩНЩ1 С#.

Глава 1i Философия ..НЕТ


Материал ЭТОЙ :r:лаэы ЯВШieТСЯ фундамеJ-IТОМ ДJm пmm:мания всего остального
материала lUiИI'и. 1Лава наЧИl!aетаК с обсуждения традициОl:Iныхвозможностеи
разработки цporpaмы в среде WtndQWS ·и ytcfJ3ы8a'f на недостатки Э'I'~го. испОЛЪ3D­
~шегосS ранее подхода. Но главной ЦeJIblQ .ЦafЦIоЙ Г.,'ШБЫ является зl:lаномство с
иае10РОМ "строительных блоков
Н

.NEТ.ТaIoIx ЮIJI! СЩ (Соmпщл Languзgе Rnntime-


общензыковая среда въmoлнеНинj. c'ffi (Coдunon 1УРе System - общая си(!Тема ТИ~
пав). CLS (Common Language Speciflcation - о(5:UJ.ензьщовые спецификации) и би.­
{)лиоте$ базовых Юlассов. Эдесь же предmп'ается вводнщ! 'иНфIilРМация о ЯЗhlКе
uрогр~ровaJrШ] С# и формате КОМlЮНOВОчtl:БЦ{ БДQЩ)В .~ раесматриваютc.JI
МеЖIJJIатформеIIЩUJ незави~ШОеть. вытенающая из· ~ОЙ npирoдJ>1 плR!J'формы
.NEТ. .и: PQ/U> си (СоIЩDОП Language fufras1:ruCture - общеязыковал инфраcтpymypa).

Глава 2. Технология создания приnо_ений на IIзыеe С#


в ;:JТОЙ Т'лаве прeдлaraетСJ1 :крат.кое описание npоцес.еа КОМПИЛRЦИИ и отладки
файлов IIСхадноro кода Д1Щ ПРOI·рамм.. написанных Н3 .Я3БIRе С#. а таюве об~-
1O'IOI CoopJ~e инструменты и те.хишюгии . Сначала вцrузнae-re. ~ . ИСПОЛЬ­
зовать КОЫIШТ1ЯТ()Р КОМаЕДJ:tой C'I'pоки (osc.e~eJ и. файлы ответдых сообщений.с#,
После этого будут рассмотрены lIекоторые из множества nЩl,eТОВ. ПРeдJIaI'aIOЩИХ
.ин.тегрирова:н:нуlО среду разработни. - ЭТО. В ч-астности. 1{>xtPam. Sha:rpDevelop.
Visua1 С# 2005 ЕХРГеБЭ .и (конечно Же) V1sua1 Studlo 2005, 1Jт же будет npедстав­
.лен: ряд a:mщoГ1fЧНЪ1X пакетOI~ с открытым ИС:ХОдИым водам (VU. NJ\nt. NDoc и т.д.).
которые на 'ВCЯ'.fCИЙ случай должен иметь .!1ЮбоЙ разработчйк .NE'Г.

Часть II~ Язык програММИРОВ'ания С#


в этой частщ ~сслt:.цуют(;я ocHoB1:Iыe ВО.8МОЖНОСТИ языка пр6граммщ:ювани.я: С#.
включая H()B~e синтаксцчесlЩе конструкции. появивI1tИеся с ВЪ1XOДO~ .NEТ 2,0,
.. Кроме TOfO. часть П поэmmомит вас с элементами crs [классы. интерфейсы' струн­
тjpьt.neречни и д~eг.aтъr) u ко:астрJlЩИJ1МИ общих типо.в .
34 Введение

Гnава З. Основы языка С#


В этой главе рассматриваются базовые конструкции языка программирования
С#. Вы освоите технику построения классов, ВhIЯСЮlТе разницу междУ nmами. ха­
рактеризуемыми значениями. и ссылчиы:ми типами, приведением к объектному
типу и восстановлением из "объектноro образа", а таюке роль moбимоro всеми ба­
зового класса System.Object. В этой же главе ПOlшзано, как ruIaтформа .NEТ за­
ставляет работать самые простые программные ICOнструкции, такие как перечни.
массивы и обработчики строк. 'Наконец. в этой главе рассматривается ряд специ­
фических для версии 2.0 вопросов. включал типы данных. для которых имеется
разрешение принимать значение null.

Гnава 4. Язык С# 2.0 и объектно-ориентированный ПОДХОД


Целью главы 4- является выяснение того. как ЯЗЫI( С# сочетается с базовыми
принципами ООП - инкапсуляцией, наследованием и полиморфизмом. После рас­
смотрения ЮIЮчевых слов и синтаксиса. используемых при построении иерархии

классов. будет выяснена роль XМL-комментариев в программном коде.

Гnава 5. Цикл существования объектов


В этой главе выясняется, как в рамках CLR с помощью сборщика мусора .NEТ
организовано управление памятью. В этой СВRЗИ вы узнаете о роли корней прило­
жения. генераций объектов и nmа System.GC. После изучения базовых вопросов в
оставшейся части главы будут рассмотрены тема объектов, преДУсматривaIOIЦИX
освобождение ресурсов (через интерфейс IDisposable). и процесс финализации
(реализуемый с помощью метода System.Object.Finalize (»).

Гnава 6. Структурированная обработка исключений


В этой главе обсуждается стрyкrypированный подход к обработке исключений
(т.е. исключительных ситуаций), которые могут возникать в среде выполнения.
Бы узнаете о ключевых словах языка С# (try, catch. throw и finally). которые
позволяют решать соответствующие проблемы. а также выясните разницу между
исключениями системного уровня и уровня ПРКjl0жения. Дополнительно В главе
обсуждаются специальные средства Visua1 Studlo 2005, призванные упростить за­
дачу выявления и обработки исключений. ускользнувших от вашего внимания.

Гnава 7. Интерфейсы и колnекции


Материал этой главы опирается на понимание принципов разработки приложе­
ний с использованием объектов и охватывает вопросы программирования на базе
интерфейсов. Вы узнаете. как определить тиI1ы' поддерживающие множество эле­
ментов поведения, как найти эти элементы поведения во время вьmОJПIения и как
выборочно скрыть такие элементы поведения. используя явн.УЮ реализацию шt­
meрфеikа. Б оставmейся части главы рассматривается пространство имен System.
Collections. с помощью котороro демонстрируется польза типов интерфейса.

Гnава 8. Интерфейсы обратного вызова, AeneraT"1 и события


Цель главы 8 заключается в разъяснении nmа делегата. Упрощенно roворя, де­
легат .NEТ- это шаблон. "указывающий~ на методы в приложении. С помощью
r

тaROl'O шабдОНэ' вы nOJl}"'taeтe БОЭМ()ЖНОС1'РСТРОИТЪ cв:cтeМh1. в которых множество


Qбъеитов могут быть евязmIЫ двусторо:щшм обменом. После выонet-mвB ВОЗNОЖ­
FЮстей использования делега-rов .NEТ(вwпoчая мнржество noэмoжностeii. rro.t!IШВ­
шихсц с версией 2.0, - НЩIpI1Мер. ahOl-шмные ме.тоДЪ1) .в главе рассматривается
юпочевое СЛОВО С# event, КОТО)XIе ИСfl().l'1b3ye-I:tя ДJm ТOГQ, <rroбыynpocrитh npоце.сс
ЦРОГРaмIYIИpOвании о UОМОЩЫО делегатов.

Глава 9. Специальные пр~емЬ! построеНИII типов


Эта гдэва поаволит вамrлубже ПОНЯТЬ во"!Мо»IВОcrи 8ЗъtRa цроrраммироuЭJiИЯ
С# путем :изучения более соверше~tных методов проrpаммцровщщя, Вы узнаете.
RaК 'ИСДользовать переrpУЗlty оцеpaциji и создавать ПOJIЬЭовэ.тельС1Ще npоrp3ммы
преобрааовamm (ЯВl'IOJ;'О и.rш неявнего), IЩR С1'РОИТЬ индексаторы ТЮIОВИ работатfo
с указателлми C-ТFЩa в файле" .cs.

Глава 1О. 'Обобщения


в СВЯЩfс разрабоо:кой _NEТ 2.0 язык прогptl.ММИрования: C:N б:ылрасmиpен с
I:I,~Ю додцержки новой возможности СТ$. с:вnзatЦi(JЙ ее тцк rIащ.mаем:blМИ обоб­
щениями (geneI1csJ- Вы увидите. что программирОвание с ПОМ()ЩblO оБQБщений
ускоряет процесс создщmя приложеицй и обеецечивает типовую беЗОПЭС1l0СТЬ.
Эдесь pa:CCM(t)Weны раЗЛl;Iчные обобщещныс 1'IIIUJ.1 из ПрОСТРЗ1-IСТВа. име:1-I System.
Co1;lcectioJls.Generic, а также 1I0НЗ:зaнQ, ,сак строить свои собственныe обобщен­
Ные методы и 'rlЦlbl (:как с orpаидчеы:ищми, так и без таневых).

Ча~ть ш. Программирование IfQМПОНО.ВОЧНЫХ бл,оков .НЕТ


в э:той части раССМQ'IpИБаеТея формат IЮмпоновочны:х блоков .NEт. Бы узнаете,
lШК разверпyrь Е CRонфи;гурировать библиQ'l'еRИ цporp~oгo ROда .NEТ, и ~c­
ви:re ввутрet-uпoю cт~тypy бинарного образа .NEТ. В этой те чаСТIi объ8СIШется.
~ атрибутов .N!CТ и 1iiОНСТРунция. М60rопO'l'O'lНl>Щ l1plЩожений, В последних rла­
вак этой час"J'Ц рассматриваются НИЗ1щуровневые в@проcы ГТаЕие Kf\К. НanpI1Мер,
объtJ1P'НЫЙ KOHтeRCT). а таюRе СШn'aJ(СИС JI семацтика CIL.

Глава 11. Компоновочнwе б1l0Q .НЕТ


с ТОЧКИ зреmmвыокоуровневогоo пццхода, кo,мnoнoВОЧfLble БJl.OJCИ- ЭТО файлы
~ ,d 11 щи "'. еке-. НО такая J-штерпретaщ.rn JЩМIIОНОВОЧНЫХ, бlIО1ЮR .NEТ очень да­
ДеIro от QисчерпpmающеЙ·. ВЫ узнаете, чем. ОТJ1ичаютсц ОДЦомо.цульные и МНОГО­
»ОДУЛЫIblе 'КOМlД)новочные 6локи и RЦ СТРОJiXтсл И ИlJСТЗЛ:ЛИJ!IУЮТСЯ такие оБЪj$­
ТI!I. Вы H~Tecь Iсонфигурировать npиватяще и оt:5щедО€ТJIЩЫе компоновочные
БJljО~. щшольауя ДЛЯ этого XМL.фaiШы ... config и 1Юмпоновочные бщжи полити­
ки поСта:вщщш. По ходу дела БУдУТ выя:снены внyrреlЦlЯЯ C'ТpY'J(тypa аАС (Global
Asэещрlу Cache - щоба:льный НЭШI(ОМПОНОВОЧНЬ1Х блоков) и роль yт:идиты IWн:фи­
rYPaIJ):IR .NEГ F'гam:eщJJ"k 2.0.

Гпава 12. Отображение типов, динамическое СВЯ3ыilаtt..е


и npограммироваliие с ПОМОЩЬЮ атрибутов
Б щcme 12 изyq:ение RОМnОН080Ч:НЫХ БJЮ1со:а .NEТ прододщэ'e'I'СЯ - эдесь рассма:­
триваетскпроцесс обнаPY1Remm ТИПОВ в epeд~ ВЬЩОШl~rШВ с помохщ.ю ПРОi::'Тран-
36 Введение

ства имен System.Reflection. С помощью этих типов МОЖНО строить приложеЮiЛ.


способные читать метаданные компоновочных блоков U Ha лету" . Вы узнаете. как
динамически активизировать и обрабатывать типы во время выполнения програм­
мы. используя дUНQJКuчеСICое связываиuе. Здесь же исследУется роль атрибутов
.NEТ (как стандартных. так и создаваемых программистом). Чтобы иллюстриро­
вать возможности применeЮiЛ обсуждавшихся подходов. в конце главы рассматри­
вается конструкция расширяемого приложения Windows Fbrms.

Глава 13. Процессы, домены приложений, контексты и хосты CLR


Здесь выполняется более глубокий анализ структуры загруженного выполня­
емого файла .NEТ. DIавная цель - иллюстрация взаимосвязи междУ процессами.
доменами приложеI;IИЙ и границами ко}{текстов. Определив эти объекты. вы смо­
жете понять, как обслуживается CLR в рамках операционной системы Windows. и
расширить свои знания о mscoree.dll. Представленная здесь информация может
оказаты;:я очень полезной при освоении материала главы 14.

Глава 14. Создание многопоточных приложений


в этой главе объясняется. как строить мноroПОТОЧНIiIе приложения. и иллюстри­
руется ряд приемов. которые вы можете использовать для создания программного

кода. безопасного с точки зрения многопоточных приложеНИЙ. В начале главы сно­


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

Затем исследуются типы пространства имен System.Threading. Здесь обсуждает­


ся множество типов (Thread. ThreadStart. и т.п.). позволяющих очень просто соз­
давать дополнительные потоки.

Глава 15. Понимание CIL и роль динамических


компоновочных блоков
В этой главе ставится две цели. В первой половине главы рассматриваются
синтаксис и семантика CIL. намного более подробно. чем в предыдУЩИХ главах.
Остаток главы посвящен выяснению роли пространства имен System.Reflection.
Emit. С помощью соответствующих типов можно строить программное обеспече­
ние. позволяющее генерировать компоновочные блоки .NEТ в памяти во время
выполнения программы. I\oМПО}Iовочные блоки. определенные и выполняемые в
памяти, формально называют дuШLМUчеCICUМU комnоновочиымu блокамu.

Часть IV. Программирование с помощью библиотек .НЕТ


к этому моменту вы уже имеете достаточно информации о язьmе С# и формате
компоновочных блоков .NEТ. Часть IV предлагает расширить ваши новые знания
и исследовать целый ряд пространств имен в рамках библИотек базовых классов,
в частности файловый ввод-вывод, слой удаленного доступа .NEт. конструкцию
Windows Fbлns и доступ к базам данных с помощью ADO.NEт.

Глава 16. Пространство имен System.IO


По названию указанного пространства имен можно догадаться, что Systern.IO
обеспечивает взаимодействие со структурой файлов и RaТалогов соответствующей
F

машины. Из этой I:iшвы вы узНаe:tе, как пporрЭММНNМИ ср~~вами м.0ЖJr0 создать


IИJЩ~) систему каталогов, как размеЩа.тъдaвю.tс:ануТри раЗЛИЧНhlX Пd­
"I:QКЩ'I (ф.овых' строIroвых,.в tш:мкrи и т.д.) И хак ВЫВОДИТЬ их олуда.

Глава 17. СериаnИЭIЦИЯ объектов


в ~ТОЙ главе рассматриваютCiЯ сервисы сериа.лиз.ации объектов Дl!IЯ I1.Лsтфор­
мы .NEТ. ~щенно говоря. сериаmзация позволяет "консервировать" сОСТ()яние
объе~та (ил:ii МНОЖ.ества свиэанныхобъeRТOВ) В пото:ке j1.J"Ш использования в бw­
щем . Д~сериализlЩия (кан вымажете догадаться сами) является процессом 113-
ВJIечеИИII объекта из потека ДЛ.iI восстановления -в памяти с целью иCnоJlЪЗOВания
Этого оБЪепта в npильжении. Пошш базовые прИ1ЩИnЫ этих процесеов, вы сможе­
те y.пp;mmпъ цроцессами сер.иализации с помощью интерфейса ISeria1izable И
:множества fЮБЫХ атрибyroв . .npeдnarаемых ,NEТ 2.0.

Глава 18.. Удапе'нное взаимодейотви,е .НЕТ


~'рек:и распроСТраненному убеждению. web-сервиcы XМL не ЯВЛЯЮ'I'с.я: еДИН­
ственным средством построепил рас.предменйых прило!Жений АЛЯ платформы
.NEТ. Из этой главы вы узнаете о слое УдаЛенного дocryпа .NE'Г. Бы yвидmе. что
CIМ подцеРЖИ'вает npocтьre возможности обмена об'Ьектами мещцу приложеJШЯ­
ми из разНых доменов и аа рааных машинах. используя семантику МВV" (marshal-
by-vзlUе- маpmали:вг по 3На'leНИЮ) и МВR '(marзhal- Ьу-rеferenсе- маРЩaJIИНI' по
ccьmкe) . По ХОду'дела вы узнаете. кaR .B деклараТИБНОЙ форме во время ВЬПIщrнепия
можно изменить .поведение распределенного .NET-прИJJожения. исподьзул XМL­
файлы конфmypaцnи.

ГlШва 19. Создание OkOH с помощью System.Windows..Forms


в ' этойгл:аве 1iачинае:rсв ваше 'знакомство с пространством имен S уз 'с enl _
Windows . Fo l'InВ. ПQДРОбно обсужцается вопрос построения традиционных npи­
ложеRи'и с графическим иНтерфейсом. пьддержившощим систеМЫ меню. ПIUJМИ
ИRструментови строки сас:rонния. как :и следует ожидать. здесь рассматриваются
различные аcnеКты.npоектировани.я форм в Visua1 Studio 2005. а дm! .NEТ2 . 0·­
цeлыйяд ТМОВ Windows Fbлns (Me nuStrip. тооlstriр:ит.п _).

Гnава 20. В'изуализация графических данных средствами 001+


ВЭ1'ой гла:веговоритсн: о ·том, :как реализовать динам.иЧес:кую визуализaщt10
графическ:их дa.IO:i:ЫX в приложенИи WIndows Fbrms. Кроме обсуждения вопросов
обрабOТКJlI ~фтlШ. цветовых даШIbIX. reoметрJolЧССRИX образов .1'1 файлов иэобра­
жеEmй. .в этой г.паве рассматриваются воnpооы проверRП: попадаЮfН в заданную об.
ласть и теXFJИНa перетаскИвinmя об'Ьеlftов в рамиах графичесROrО ин-терфейса, вы
уэнаете о новом. формше ресурсов .NEГ. который. пах в.ь.t уже моясете. догадываться
.и этому MOMesтy. ОСНован на ХМ1....npeдстав.itении данных.

Глава 21. Испоnьэование эле.ментов управлекияWiпdоws Forms


Этз "Глава НВJlRеТСll пdследней из глав ХНИТIiJ, связанных с обсуждением пряло·
жений для Wfndows, й зде<:ь будет ' рассмотрено множество элеменroв графического
ИВТq>феЙса. преДлагаемых в .NEт Framewotk 2.0. вы Raучи-гесъ исuользовЭТI. раз-
38 Введение

личные элементы управления Windows Fonns. узнаете о приемах разработки диа­


логовых окон и наследовании форм. В этой же главе рассматривается возможность
построения пользовательских элементов управления Windows Fbnns. которые мож­
но интегрировать в ШЕ (lntegrated Development Envlronment - интегрированная
среда разработки).

Глава 22. Доступ к базам данных с помощыo АDо.NЕт


ADO.NEТ - это АР! (Application ProgrammJng lntеласе - интерфейс программи­
рования приложений) доступа к данным для платформы .NEт. Вы увидите. что с
тИIJами ADO.NEТ можно взаимодействовать как на связном уровне ADO.NEт. так
и несвязном. В этой главе будут рассмотрены оба эти режима ADO.NEТ. а также
некоторые новые воэможности. связанные с .NEТ2.0. включая модель источника
данных. построители строк соединений и асинхронный доступ к базам данных.

Часть У. WеЬ-приложения и Web-сервисы XML


Эта часть книги посвящена созданию Web-приложений ASP.NEТ и Web-серви­
сов XМL. Из материала первых двух глав этой части вы узнаете. что ЛSР.NEТ 2.0
является значительным шагом вперед по сравнению с ASP.NEТ l.x и предлагает
множество новых возможностей.

Глава 23. Web-страницы и Web-элеменТbI управления ASP.NEТ 2.0


В этой rлаве начинается изучение Web-технологИЙ. поддерживаемых в рамках
платформы .NEТ с помощью ЛSР.NEТ. Вы увидите. что прогpaммный нод сценариев
серверной стороны теперь заменяется Иреа.llЬНЫМИ~ объектно-ориентированными
язьmами (такими как С#, vв .NEТ и им подобными). Здесь буJIYГ рассмотрены КJПO­
чевые для ЛSР.NEТ вопросы. такие как работа с файлами. содержащими внеIШПIЙ
программный код поддержки, роль Web-элементов управления ASP.NEТ, использо­
вание элементов управления, связанных с контролем ввода. и взаимодействие с
новой моделью Иmаблона страницы". предлагаемой ASP.NEТ 2.0,

Глава 24. WеЬ-приложения ASP.NEТ 2.0


эта глава расШИрЯет ваши знания о возможностях ASP.NEТ с помощью рас­
смотрения различных способов управления состommем объектов в рамках .NEт.
Подобно классической модели ЛSР. npиложение ЛSР.NEТ позвол.яет создавать фай­
лы cook1e. а также переменные уровня приложения или сеанса. Однако ЛSР.NEТ
предлarает и новую технологшо управления состояниями - это кэш приложения: .

Рассмотрев многочисленные способы обработки состояний в ASP.NEт. вы сможе­


те выяснить роль базового класса System.HttpApplicatioI1 (скрытого в файле
Global.asax) и научиться динамически менять поведение Web-приложеиия в сре­
де вьшолиения, испол:ьзуя файл Web.config.

Глава 25. Web-сервисы XML


В этой последней главе книги выясняется роль Web-сервисов XМL и рассматри­
ваются возможности их создания в рамках .NEТ. ГРубо говоря. Web-сервuc- это
компоновочный блок. активизируемый с помощью стандартных НТГР-зanросов .
BBeдetl~e 39
ПреИМуЩество ЭТОГО подхода ~aюnoчаетсн в том. что HrтP ЯВ1ШетЦJ: eeT~ прq­
Токоло'М. npименяемы:м почти повсеместно. поэтому O}'J дрекра,сtю UQДXO,lWi:1' ДЛЯ
йспользовa:mm в распределенных CIfCTeMax. нейтралъfJЫX в ОТНОд:IetIЩJ ра.'iЛИЧНЪ1X
IШатформ й языков. Эдесь же вы уэпаете о мношеСТIlе со:путствующщ технОJ1IОI'ИЙ
(WSDL, SOAP и UDDIJ. «оторы:е обеспечив;uoт га.Р~О:ЮП\:) В3а»Модейр1'13ИЯ Web-cep-
виса п ВнeIПн.еtо ltJIИе~.

ИСХОДНЫЙ КОД примеров книги


Прогрзм:мды::Щ над всех дршyrеро~ из этОй RНЮ'И (с ТDЧНОСТЬЮ ДО встречающихея
кое-где l'IеБОJПi>llIЩ фра:гмеитов) доступен ДЛЯ загруз:ки и3 раздела ИСХОДl10rо Iro,ца
Web-узла иэдательетва. Быполн:ив поИСк по названию книrи, перейдите па ее "до­
машнюю· cтpшnщy . откуда в~сможете загрузи,т.ь файл 7/. zip с fiCXOдньtм КОДОМ
примеров . После раСЦа1ЩIЩИ содержиМОТ'О ЭТОГО файла вш обfIаружите со ответ­
СТВ~ЩИЙ npогрaмщrы:й код. разделенный по tлавам.
Обрат'ите Bl-ШМа1Ще H~ ТО, ЧТО В книrев разДeJ1aJC с названием Исходн.ый 1<:00
уиа~ано. ГАе СОДер3mТСЯ прОllРaммJ'JblЙ:КОД обсущдаёмьго примера. Этот npоrpaм­
мI'Jый нод МОЖНО зarруrштЬ в VjsuW stud10 2005 Д1Ш npoверки и модификации.

ИОХОАныЙ "о,ц, 8 таком при-ме'Jан.ии 'Ук<!з~!Ваетi::я сqЫЛJql на I(атэ.лor, содержащий ИСХОДНЫЙ "ОД
соотвеТСтвующего примера.

ДлЯ ЗЩ'рузкиnримера откройте Файл *.sln в YRазанвом пОДI(ЭТWIОl'е.

Связь с автором
Если У вас :во:ш:mсН)'Т BOIipQCbl в связи С иоходным кqдом примеров, потреб­
ность в дЩНшнителъных раэъяснеJllUD( или просто желание поделитЬ<'.JI СВОИМИ

.цдеими в QТRоmении ru:ra:rформы .NEТ, без всяхоro стеспе.ни.ч IIИUIИТe мне на мой
~eC ЭJreRТровнuй почты а t roelsen@Irite'rte<:hTra:tni n g. с от (чтобы трантпро­
~т.ь, что Ba1ne "со6БJцение не она.жетсл в Roрз~mе моей почтовой системы. укажите
·C#1E~ встро:ке 'темы).
Я постараюсь сделать .все ВОЗМDжное. чтобы ответить в при~м:.леМhlе CPOKIl, во
прошу учесть TD. что Я. JtaR и вы. время от Вр6мени бываю, очень занят, Еслн а не
QТ'ВечaIO в Течение недели или lI!JY'X. то, знайте. "<11'0 это не.из вредности и не потому.
что Jf не хочу общатьм с вами . .н просто зa1l.я.т (или. если ,выпад о сЧаС1:'ъе. НЮ!;0)JCyСЬ
где-то на o'JДЫXe),
T~ что, :вперед!, Спасибо за то. что вы кynшm эту книгу (W1И. jtЮ( ~.
~i:J.JЛНН)i'Jm в вее :в книжном магазине. об;цуМЫВая возможвоC'rЬ ее понудк:и). Я ,ва.­
деюсь, 'rtO вам будет IIpИ.flт.Но читать ее . и им CMow.eтe прим:ени1Ъ nQлyчeIщыIe эва­
щш в блш'орьдвых целях.

Берегцте себя.
8нiJрю Троелсен.
40 Введение

От издательства
Вы, читатель этой книги, и есть главный ее критш( и комментатор. Мы ценим
ваше мнение и хотим знать, что было сделано нами правильно, что можно было сде­
лать лучше и что еще вы хотели бы увидеть изданным нами. Нам интересно услы­
шать и moбые дрyrие замечш-uш, которые вам хотелось бы высказать в наш адрес.
мы ждем ВaIIIИX комментариев и надеемся на них. ВЫ можете приспать нам бу­
мажное или электронное письмо, либо просто посетИJЪ наш Web-сервер и оставить
свои замечания там. Одним словом, moбым удобным для вас способом дайте нам
знать, нравится или нет вам эта книга, а также выскажите свое мнение о том, как

сделать наши книги более интересными для вас.


Посылая письмо или сообщение, не забудьте указать название книги и ее авто­
ров, а также ваш обратный адрес. мы внимательно ознакомимся с вашим мнением
и обязательно учтем его при отборе и подготовке к изданию последующих книг.
Наши координаты:

E-mail: info@williamspublishing.com
~: http://www.williamspublishing.com
Информация для писем из:

России: 115419. Москва. а/я 783


Украины: 03150. Киев, а/я 152
,

ЧАСТЬ I
Общие сведения
о я3ыIеe С#
и платформе .NET

в этой часТи ....


Глава 1..филоСОфИЯ ..NEТ
Глава 2. Технология создани.я прилажениЙ.на s:lзыке С#

ГЛАВА 1
Философия .NEТ

К аждые несколько лет программист должен быть готов кардинально обнов­


лять свои знания, чтобы идти в HOry С новыми технологиями. Языки (С++,
Visua1 Bastc 6.0. Java), каркасы приложений (MFC, AТL, SТL) и архитектуры (СОМ,
CORВA, EJB), которые сегодня составляют Изолотой фонд" разработки програм­
много обеспечения, в будущем непременно уступят место чему-то более совершен­
ному или, по крайней мере, более новому. Несмотря на разочарование, которое вы
можете ощущать при обновлении своей базы знаний, это неизбежно. ПЛатформа
.NEТ - это сегодняшнее предложение Мtcrosoft в области разработки программно­
го обеспечения.
Целью этой главы является построение концептуального фундамента, необхо­
димого для успешного освоения всего остального материала книги. DIaвa начина­
ется с обсуждения ряда вопросов .NEТ, ОТНOCЯIЦИXСЯ к высокому уровню, - таких
как компоновочные блоки, CIL (общий промежуточный язык) и JIТ-компиляция
Uust-in-time- точно к нужному моменту). Вдобавок к вводному обзору некоторых
ключевых возможностей языка программирования С#, будет также обозначена
взаимосвязь между различными элементами каркаса .NEТ, такими как CLR (общая
языковая среда выполнения), CТS (общая система типов) и CLS (общие специфика­
ции языка). как вы вправе ожидать, эти темы будут исследоваться более подробно
в других частях книги.

Эта глава также содержит обзор возможностей, предлагаемых библиотеками


базовых классов .NEТ, для обозначения которых иногда используют аббревиатуру
BCL (Base Class Libraгies - библиотеки базовых классов) или, как альтернативу,
FCL (Framework Class Librartes - библиотеки каркасных классов). Наконец, в главе
обсуждается независимая от языков и платформ сущность платформы .NEТ (это
действительно так- .NEТ не замыкается на операционной системе Windоws).

Предыдущее состояние дел


Перед рассмотрением специфики .NET будет полезно рассмотреть некото­
рые проблемы, стимулировавшие появление предлагаемой сегодня платформы
Мiсrоsоft. Чтобы получить соответствующее представление, давайте начнем зту
главу с краткого урока истории, чтобы напомнить об истоках и понять ограниче­
ния, существовавшие в прошлом (в конце концов, признание существования про­
блемы является первым шагом на пути ее решения). После этого мы обратим наше
внимание на многочисленные преимущества, которые обеспечиваются языком С#
и платформой .NEТ.
44 Часть 1. Общие сведения о языке С# и платформе .NET

Подход СjWiпЗ2 API


Традиционно разработка программного обеспечения для операционных систем
семейства Windows предполагает использование Языка программирования С в со­
четании с Windows АРI (Application Programming Interface - интерфейс програм­
мирования приложениЙ). Несмотря на тот факт. что в рамках зтого проверенного
временем подхода было создано очень много вполне успешных приложений, мало
кто станет оспаривать то, что процесс создания приложений непосредственно с
помощью АРI оказывается очень трудоемким делом.
Первая очевидная проблема заключается в том, что С является очень лаконич­
ным языком. Разработчики программ на языке С вынуждены "вручную" управлять
памятью, использовать безобразную арифметику указателей и ужасные синтакси­
ческие конструкции. К тому же, поскольку С является структурным языком про­
граммирования, ему не хватает преимуществ, обеспечиваемых объектно-ориенти­
рованным подходом (здесь можно вспомнить о "макаронных" программах). Когда
вы объединяете тысячи глобальных функций и типов данных, определенных в
рамках Wln32 API, с языком, который и без того выглядит устрашающе, не следУет
удивляться тому, что среди используемых сегодня программ оказывается так мно­

го ненадежных.

Подход C++/MFC
Огромным шагом вперед по сравнению с подходом, предполагающим использо­
вание C/API, явился переход к применению языка программирования С++. Во мно­
гих отношениях язык С++ можно рассматривать, как объектно-ориентированную
надстройку над С. Поэтому, хотя при использовании С++ уже можно использовать
преимущества известных "краеугольных камней ООП" (инкапсуляция, наследова­
ние и полиморфизм), зтот подход оставляет программиста во власти многих болез­
ненных аспектов языка С (управление памятью "вручную", безобразная арифмети­
ка указателей и ужасные синтаксические конструкции) .
Несмотря на сложность, сегодня существует множество каркасов программи­
рования на С++. Например, MFC (Microsoft Foundation Classes - библиотека базо­
вых классов Wcгosoft) снабжает разработчика набором С++-классов, упрощающих
создание Wiп32-приложениЙ . DIавной задачей MFC является представление "раз­
умного подмножества" Wln32 АР! в виде набора классов, "магических" макросов и
средств автоматического генерирования программного кода (обычно называемых
мастерами). Несмотря на очевидную пользу указанного каркаса приложений (как
и многих других средств разработчика, использующих С++), программирование на
С++ остается трудной задачей, и на этом пуги нелегко полностью избежать ошибок
ввИдУ ·тяжелоЙ наследственности", обусловленной связью с языком С.

Подход Visual Basic 6.0


Благодаря искреннему желанию насладиться более простой жизнью, многие
программисты ушли от "мира каркасов" приложений на базе С(++) к более друже­
ственным языкам, таким, как, например, VisuaI Basic 6 .0 (VВ6). Язык VВ6 стал по­
пулярным благодаря тому, что он дает возможность строить сложные ннтерфейсы
пользователя, библиотеки программного кода (например, СОМ-серверы) и системы
f

Глава 1. Философия .NET 45


ДOC'I)'I1а к данным, затрачивая минимум усилий. В сравнении с MFC, VВ6 еще глуб­
же скрывает от глаз разработчика сложность Win32 ЛPI, используя для этого целый
ряд интегрированных мастеров, внутренних типов данных, классов и специфиче­
ских для VВ функций.
IЛавным недостатком VВ6 (который был устранен в Visua1 Basic .NEТ) является
то, что VВ6 является, скорее, Мобъектно-осведомленным" языком, а не полноцен­
ным объектно-ориентированным. Например, в VВ6 программисту не позволяется
связывать типы отношениями Мподчиненности" (т.е. нет классического наследова­
ния) и нет внутренней поддержки конструкции параметризованных классов. Кроме
того, VВ6 не дает возможности строить многопоточные приложения, если только
вы не готовы Мспуститься" до низкоуровневых вызовов Win32 API (что в лучшем
случае достаточно сложно, а в худшем - опасно).

Подход Java/J2EE
Было предложено использовать Java. Язык программирования Java является
(почти) полностью объектно-ориентированным и имеет синтаксические корни в
С++. Многие знают, что поддержка межплатформенной независимости - далеко
не единственное преимущество Java. Java (как язык) избавлен от многих синтак­
сических несообразностей С++. Java (как платформа) предлагает программисту
большое число встроенных Мпакетов", содержащих различные определения типов.
С помощью этих типов, используя "только Java", можно строить приложения, пред­
лагающие сложный интерфейс пользователя, обеспечивающие связь с базами дан­
ных, обмен сообщениями или работу клиента в Web.
Хотя Java - очень злегантный язык, его потенциальной проблемой является то,
что использование Java в цикле разработки обычно означает необходимость ис­
пользования Java и для взаимодействия клиента с сервером. как следствие, Java
не позволяет возлагать большой надежды на возможности языковой интеграции,
так как это идет вразрез с декларируемой целью Java (единый язык программи­
рования для всех задач). Реальность, однако, такова, что в мире существуют мил­
лионы строк программного кода, которым бы идеально подошло взаимодействие
с более новым программным кодом. К сожалению, Java делает эту задачу пробле­
матичной.
Java в чистом виде просто не подходит для многих приложений, интенсивно
использующих графику или сложные вычисления (в этих случаях скорость работы
Java оставляет желать лучшего) . Для таких программ в соответствующем месте вы­
годнее использовать язык более низкого уровня (например, С++). Увы, пока Java не
обеспечивает более широкие возможности доступа к "чужеродным" API, истинная
интеграция различных языков оказывается практически невозможноЙ.

Подход СОМ
Модель СОМ (Component Object Model- модель компонентных объектов) была
предыдущим каркасом разработки приложений Мiсrosoft. По сути, СОМ - это ар­
хитектура, Мзаявившая" следующее: если lCЛQ.Cс будет noстроен в соответствии
с nравuлами СОМ, то получится блок двоичного када .мноzoкратноzo исnoльзо­
ванuя.
46 Часть 1. Общие сведения о языке С# и платформе .NET

Прелесть двоичного СОМ-сервера в том. что способ доступа к нему не зависит


от языка . Поэтому программисты. использующие С++. могут строить СОМ-классы.
npигодные для использования в VБ6. Программисты. применяющие Delpbl. могут
использовать СОМ-классы. построенные С помощью С. и т.д . Однако. и вы. возмож­
но. об этом знаете. независимость СОМ от языка несколько ограничена. Например.
нет возможности получить новый СОМ-класс из уже существующего (поскольку
СОМ не предлагает поддержки классического наследования). Вместо этого для ис­
пользования типов СОМ-класса вам придется указать несколько неуклюжее отно­
шение "обладания".
Еще одним npeимуществом СОМ является npозрачность дислокации. используя
такие конструкции. как идентификаторы приложения (АррID). "заглушки" и "заме­
стители" в среде выполнения СОМ. программист может избежать необходимости
непосредственного обращения к сокетам. RPС-вызовам и другими низкоуровневым
злементам . Рассмотрим. например. следующий программный код VБ6 СОМ-кли­
ента.

, Этот бnох прогрuacного хода VВб ..о.ет аХ'1'Иllизировать СОМ-xnасс,


, созд&JUUIЙ на JUDбо.. .зыхе, поддер.ива.пце.. СОМ, и раз..ещеННЫЙ
, в JUDбой точхе сети (ВJCJIJ:)ча. вашу noxa..nьHYJO ..ашину) .
Dim с as MyCOMClass
Set с = New MyCOMClass , Размещение выя с няет с я с п о м о щью AppID.
c.DoSomeWork

Хотя СОМ можно считать очень успешной объектной моделью. внутренне она
чрезвычайно сложна (по крайней мере. пока вы не потратите несколько месяцев на
изучение ее внутренних механизмов - особенно если вы программируете на С++) .
С целью упрощения npоцесса разработки бинарных СОМ-объектов было создано
множество каркасов разработки приложений с поддержкой СОМ. Среди них. на­
пример. библиотека ATL (Active Тemplate Library - библиотека активных шабло­
нов). которая обеспечивает еще одно множество С++-классов. шаблонов и макро­
сов. упрощающих создание СОМ-типов.
Многие другие языки также в значительной степени скрывают инфрастрyк'Iy­
ру СОМ оТ глаз программиста. Однако поддержки самого языка оказывается не­
достаточно для того. чтобы скрыть всю сложность СОМ. Даже при использовании
относительно простого совместимого с СОМ языка (например. VБ6). вы все равно
вынуждены бороться с "хрупкими" параметрами регистрации и многочисленными
npоблемами. связанНыми с инсталляцией приложений (в совокупности называе­
мыми "кошмаром DLL") .

ПОДХОД Windows DNA


Ко всем указанным выше сложностям еще добавляется такая мелочь. как
Интернет. за последние несколько лет Мiсrоsoft добавила в свое семейство операци­
онных систем и других продуктов множество связанных с Интернет возможностей.
К сожалению. создание Web-npиложений в рамках совместимой с СОМ архитекту­
ры Windows DNA (Distгibuted interNet Applications Arcbltectuгe - архитектура рас­
пределенных сетевых приложений) также оказывается очень непростым делом.
Не которая доля этой сложности вытекает из того простого факта . что Windows
DNA требует использования множества технологий и языков (ASP. НТМL. XМL.
JavaScrlpt. VБSсгlрt. а также СОМ(+) и АР! доступа к данным. например АОО).
1'"

Глава 1. Философия .NET 47


Одной из проблем является то, что с синтаксической точки зрения многие из этих
технологИЙ совершенно не связаны одна с другой. Например, в JavaScript исполь­
зуется синтаксис, во многом подобный С, а VВScript является подмножеством VВ6.
СОМ-серверы, созданные для работы в среде выполнения СОМ+, по виду сильно
отличаются от АSР-страниц, которые их вызывают. Результат- чрезвычайно за­
путанная смесь технологий.
К тому же, и зто, возможно, самое важное, каждый язык и каждая теХНОЛОгия
имеют свои собственные системы типов (которые могут быть совершенно не похо­
жими одна на другую). Например, нельзя сказать, что ~int" в JavaScript и Mlnteger"
в VВ6 означают в точности одно и то же.

Решение .НЕТ
Слишком много для короткого урока истории. Основным выводом является то,
что жизнь программиста Windows была трудна. Каркас .NEТ Framework является
достаточно радикальной ~силовой" попыткой сделать нашу жизнь легче. Решение,
предложенное .NEТ, предполагает ~изменить все" (извините, вы не можете обви­
нять посыльного за такое известие). Вы поймете из дальнейшего материала книги,
что .NEТ Framework- это совершенно новая модель для создания систем как в
семействе операционных систем Windows, так и множестве операционных систем,
отличных от систем Microsoft, таких как Мас OS Х и различные варианты Un1x/
Linux. Чтобы зто продемонстрировать, вот вам краткий список некоторых базовых
возможностей, обеспечиваемых .NEТ.

• Полноценная возможнocmь взашиодейcmвия с существующим npoгpaммным


кодом. Это (конечно) хорошо. Существующие бинарные СОМ-объекты мо­
гут комбинироваться (т.е. взаимодействовать) с более новыми бинарными
.NЕТ-объектами и наоборот. Кроме того, сервисы PInvoke (Platfoгm Invocation
Serv1ces - сервисы вызова платформ) позволяют вызывать библиотеки на ба­
зе С (ВlUlЮчая АР! операционной системы) из программного кода .NEт.

• Полн.ая и moтальная интеграция язъucов. В отличие от СОМ, платформа .NEТ


поддерживает межъязыковое наследование, межъязыковую обработку ис­
ключений и межъязыковую отладку.

• ОбщиЙ.механизм ВЫnOJlНeния npoгpaмм для всех язъucов с noддeржкой .NEТ.


Одной из особенностей этого механизма является четкий набор типов, ~по­
нятных" каждому языку.

• Библиотека базовых классов. Эта библиотека позволяет избежать сложно­


стей прямого обращения к АР! и предлагает согласованную объектную мо­
дель, используемую всеми языками с поддержкой .NEТ.

• Omcyтствие детализации СОМ. В собственном бинарном .NЕТ-объекте не


будет места для IClassFactory, IUnknown, IDispatch, IDL-кода и ~злобных"
типов данных наподобие VARIANT (BSTR, SAFEARRAY и т.д.).
• Упрощенная модель uн.cmaлляциu. Согласно спецификациям .NEТ, нет необ­
ходимости регистрировать соответствующую бинарную единицу в реестре
системы. К тому же .NEТ вполне допускает существование множества версий
одного *.dll на одной машине.
48 Часть 1. Общие сведения о языке С# и платформе .NET

На основе информации этого списка вы. вероятно. уже сами пришли к заклю­
чению. что платформа .NEТ не имеет ничего общего с СОМ (за исключением того.
что оба зти каркаса разработки приложений исходят из MIcrosoft). Фактически
единственным способом взаимодействия типов .NEТ и СОМ оказывается исполь­
зование возможностей слоя взаимодействия .

ЗIМIЧIНМI. Описание возможностей слоя взаимодействия .NET (включая Plnvoke) выходит за рам­
ки зтой книги. Если вам потребуется подрОбное освещение этого вопроса, обратитесь к моей
книге СОМ and .NEТ /nteroperability (ApreSB, 2002).

Главные компоненты платформы


.NEТ (CLR, CTS и CLS)
Теперь. когда вы знаете о некоторых преимуществах. обеспечиваемых .NEТ.
давайте рассмотрим три ключевых (и взаимосвязанных) компонента. которые и
обеспечивают эти преимущества: CLR. cгs и CLS. С точки зрения программиста,
.NEТ может интерпретироваться как новая среда выполнения программ и всеобъем­
лющая библиотека базовых классов. Слой среды выполнения здесь называется
C1R (СоmmопLanguage Runtime - общеязыковая среда выполнения). DIавной за­
дачей CLR являются размещение. загрузка и управление .NЕТ-типами по вашему
указанию. Кроме того. CLR отвечает за ряд низкоуровневых вопросов. таких. как.
например. управление памятью и проверка безопасности.
Другим строительным блоком платформы .NEТ является CТS (Соmmоп 1Уре
System - общая система типов). Спецификации CТS полностью описывают все
возможные типы данных и программные конструкции. поддерживаемые средой
выполнения. указывают. как зти злементы могут взаимодействовать друг с другом
и как они представляются в формате метаданных . NEТ (более подробная информа­
ция о метаданных будет представлена немного позже).
Вы должны понимать. что конкретный язык. совместимый с .NEТ. может и не
поддерживать абсолютно все возможности. определенные CГS. В связи с зтим ис­
пользуются связанные спецификации CLS (Соmmоп Langиage SpecIftcation - обще­
языковые спецификации). которые определяют подмножество общих типов и про­
граммных конструкций. понятных всем языкам программирования. совместимым
с .NEТ. Позтому. если создаваемые вами .NЕТ-типы опираются только на возмож­
ности. соответствующие CLS. вы можете пребывать в уверенности. что исполь­
зовать их сможет любой совместимый с .NEТ язык. А если вы используете типы
данных или программные конструкции. выходящие за пределы CLS. вы не можете
гарантировать. что с вашей библиотекой программного .NЕТ-кода сможет взаимо­
действовать любой язык программирования .NEт.

Роль библиотек базовых классов


в дополнение к спецификациям CLR и CГS/CLS. платформа .NEТ предлагает
библиотеку базовых классов. доступную всем языкам программирования .NEт. Эта
библиотека базовых классов не только инкапсулирует различные примитивы. та­
кие как потоки. файловый ввод-вывод. визуализация графики и взаимодействие с
r

Глава 1. философИЯ .NET 49


различными внешними устройствами, но и обеспечивает поддержку целого ряда
сервисов, необходимых для большинства современных приложениЙ.
Например, библиотеки базовых классов определяют типы, упрощающие доступ
к базам данных, работу с XМL, поддержку программной безопасности и создание
Web-приложений (а также обычных настольных и консольных приложений) кли­
ента. Схема высокоуровневых взаимосвязей между CLR, crs, CLS и библиотекой
базовых классов показана на рис. 1.1.

Би6лиотеК8 6830BIoII КЛ8ССОВ

06щеязыковая CPeДI выполнения

Рис. 1.1. CLR, CTS, CLS и библиотека базовых классов

Роль языка С#
С учетом того, что приНI~ПЫ . NEТ так радикально отличаются от предшествую­
щих технологий, Мiсrosоft разработала НОвый язык программирования, С# (произ­
носится "си-диез"), специально для использования с зтой новой платформой. Язык
С# является языком программирования, по синтаксису очень похожим на Java (но
не идентичным ему). Однако называть С# "переработанным" вариантом Java будет
неверно. С#, как и Java. основан на синтаксических конструкциях С++. Так же, как
и Java, С# можно называть "рафинированной" версией С++ - в конце концов, зто
языки одного семейства.
Многие синтаксические конструкции С# построены с учетом решений, приня­
тых в Visual Basic 6.0 и С++. Например, как и в VВ6, в С# поддерживаются фор­
мальные свойства типов (в противоположность традиционным методам get и set) и
возможность объявления методов с переменным числом аргументов (через масси­
вы параметров). Подобно С++, в С# позволяется перегрузка операций, а также соз­
данне структур, перечней и функций обратноro вызова (посредством делегатов).
Благодаря тому, что С# является гибридом множества языков, он является про­
дуктом, который синтаксически так же "чист", как Java (если не "чище"), почти так
же просТо как VВ6, и обладает почти такой же мощью и гибкостью, как С++ (без со­
ответствующих "ужасных" конструкций) . По сути, язык С# предлагает следующие
возможности (многие из которых присущи и всем другим языкам программирова­
ния, обеспечивающим поддержку .NEТ).
50 Часть 1. Общие сведения о языке С# и платформе .NET

• Не требуется никаких указателейl Программы на С# обычно не требуют пря­


мого обращения к указателям (хотя имеется возможность получить к ним до­
ступ на более низком уровне, еCJШ вы сочтете зто абсолютно необходимым).

• Автоматическое управление памятью через сборку мусора. По этой причине


в С# не поддерживается ключевое слово delete.
• Формальные синтаксические конструкции для перечней, структур и свойств
классов.

• Аналогичная С++ перегрузка операций для пользовательских типов, но без


лишних сложностей (например, вам не требуется контролировать Uвозвраще­
ние *Шз для связывания").

• В С# 2005 имеется возможность строить общие типы и общие члены с ис­


пользованием синтаксиса, очень похожего на шаблоны С++ .

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


нии интерфейсов.

• Полная поддержка технологии аспектно-ориентированного программирова­


ния (АОП) через атрибуты. Эта ветвь разработки ПОзволяет назначать харак­
теристики типам и их членам, чтобы уточнять их поведение .

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


го Мiсrosoft в связке с платформой .NEТ, является то, что получаемый с помощью
С# программный код может выполняться только в среде выполнения . NEТ (вы не
сможете использовать С# для построения Uклассического" СОМ-сервера или авто­
номного приложения Wln32 API). Официальный термин. который используется для
описания программного кода. предназначенного для среды выполнения .NEТ.­
управляемый nрогра.ммныЙ "ад (managed code). Бинарный объект. содержащий
такой управляемый программный код. называется "омnoновочным бло"ом (под­
робнее о компоновочных блоках мы поговорим немного позже). С другой стороны.
программный код. который не может непосредственно управляться средой выпол­
нения .NEТ. называется неуправляемым npoгpa.ммным "адом (unmanaged code).

Другие языки программирования


с поддержкой .NET
Вы должны понимать. что С# является не единственным языком. ориентиро­
ванным на платформу .NEТ. Когда платформа .NEТ была впервые представлена
общественности на Профессиональной конференции разработчиков Мiсrosоft в
2000 году. ряд производителей объявили , что они уже разрабатывают версии СООТ­
ветствующих компиляторов. СОвместимые с .NEТ. На момент создания ЗТОй книги
десятки различных языков подверглись влиянию .NEТ. В дополнение к пяти язы ­
кам. которые предлагаются в Visua1 Studto 2005 (С#. J#. Visua1 Basic .NEТ. Managed
Extensions для С++ и JScript .NE11. имеются также .NEТ-комnилятoры для Smallta1k.
COBOL и Pasca1 (это далеко не полный перечень).
Материал ЭТОй книги почти исключительно посвящен языку С#. но в табл. 1.1
приводится список других языков программирования, совместимых с . NEТ, и ука­
зано. где найти более подробную информацию о них (учтите. что соответствующие
адреса URL могут измениться) .
f

Глава 1. ФилосОфия .NET 51


Твблица 1.1. Некоторые из языков программирования, совместимых с .NET

Адрес Web-страницы языка .НЕТ Описание

http://www.oberon.ethz.ch/oberon.net "Домашняя" страница Active ОЬегоп .NEТ

http://www.usafa.af.mil/df/dfcs/bios/ "Домашняя" страница А# (порт Ada для


mcc_html/a sharp.cfm платформы .NEТ)

http://www.netcobol.com Для тех, кого интересует COBOL .NEТ


http://www.eiffel.com Для тех, кого интересует Eiffel .NEТ

http://www.dataman.ro/dforth Для тех, кого интересует Forth .NEТ

http://www.silverfrost.com/ll/ftn95/ Для тех, кого интересует Fortran .NEТ


ftn95 fortran 95 for_windows.asp
http://www.vmx-net.com Оказывается, доступен даже Smalitalk .NEТ

Следует учесть, что информация табл. 1.1 не является исчерпывающей. Списки


компиляторов для .NEТ имеются на многих Web-узлах. и один из таких списков
должен быть на странице http://www . dotnetpowered. сот/ 1anguages. aspx
(опять же, точный адрес URL может измениться). Я рекомендую посетить зту стра­
ницу, поскольку вас непременно заинтересуют хотя бы некоторые из языков .NEТ
(может. кому-то понадобится LISP .NE11.

Жизнь в многоязычном окружении


Б начале процесс а осмысления разработчиком языково-агностической при­
роды платформы .NEТ, у него возникает множество вопросов и прежде всего. сле­
дующий: "Если все языки .NEТ при компиляции преобразуются в "управляемый
программный код", то почему существует не один, а множество компиляторов?".
Ответить на этот вопрос можно по-разному. Бо-первых, мы, программисты, бы­
ваем очень привередливы, когда дело касается выбора языка программирования
(я здесь тоже не исключение). Некоторые из нас предпочитают языки с многочис­
ленными точками с запятыми и фигурными скобками. но с минимальным набором
ключевых слов. Другим нравятся языки, предлагающие более ·человеческие" син­
таксические лексемы (как VisuaI Баsiс .NE11. А кто-то не пожелает отказываться от
своего опыта работы на большой ЭБМ и захочет перенести его на платформу .NEТ
(используя СОБОL .NE11.
А теперь скажите честно: если бы Мiсrosоft предложила единственный ·офици­
альный" язык .NEТ, например, на базе семейства БASIС, то все ли программисты
были бы рады такому выбору? Или если бы "официальный" язык .NEТ был осно­
ван на синтаксисе Fortran, то сколько людей в мире вообще проигнорировало бы
платформу .NEТ? поскольку среда выполнения .NEТ демонстрирует меньшую за­
висимость от языка, используемого для построения управляемого программного

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


обмениваться скомпилированными компоновочными блоками со своими коллега­
ми, другими отделами и внешними организациями (не обращая внимания на то,
какой язык .NEТ используется там).
52 Часть 1. Общие сведения о языке С# и платформе .NET

Еще одно полезное преимущество интеграции различных языков .NEТ в одном


унифицированном программном решении вытекает из того простого факта. что
каждый язык программирования имеет свои сильные (а также слабые) стороны .
Например. некоторые языки программирования имеют превосходную встроеJШYlO
поддержку сложных математических вычислений. В других лучше реализованы
финансовые или логические вычисления. взаимодействие с центральными ком­
пьютерами и Т.д. Когда преимущества конкретного языка программирования объе­
диняются с преимуществами платформы .NEт. выигрывают все.
Конечно . вы можете разрабатывать программное обеспечение. не выходя за
рамки своего любимого языка .NEт. Но, изучив синтаксис одного языка .NEТ, вам
будет очень легко освоить любой другой. Это тоже очень выгодно, особенно кон­
сультантам. Если вашей специализацией является С#, но вы оказались на узле
клиента, который "привязан" к Visual Basic .NEТ, то сможете почти сразу разобрать
соответствующий программный код (поверьте!), воспользовавшись указанным пре­
ИмyIЦеством .NEт. На STOM и остановимся.

Компоновочные блоки. NET


Независимо от того, какой язык . NEТ вы выберете для программирования, вы
должны понимать, что хотя бинарные .NЕТ-единицы имеют такие же расширения
файлов, как СОМ-серверы инеуправляемые программы Win32 (*.dll или *.ехе),
их внутреннее устройство совершенно иное. Например, бинарные .NЕТ-единицы
* . d 11 не зкспортируют методы для упрощения коммуникации со средой выпол­
нения СОМ (поскольку .NEТ- зто не СОМ). Бинарные .NЕТ-единицы не описыва­
ются с помощью библиотек СОМ-типов и не регистрируются в реестре системы .
Наверное, самым важным является то, что бинарные .NЕТ-единицы содержат не
специфические для платформы инструкции, а независимые от платформы IL-ин­
струкции (Iintennediate Language - промежуточный язык) И метаданные типов. На
рис . 1.2 это показано схематически .

Исходный код
Компилятор с#
С#
.~

Исходный КОД
Компилятор Perl .NEТ
Perl.NEТ IL-инструкции
• и

метаданные

Исходный КОД (*:dll или *.ехе)


Компилятор COВOL .NET
COВOL .NET
• •

Исходный код
Компилятор Managed С++
Managed С++

Рис. 1.2. Все . NEТ -компиляторы генерируют IL- инструкции и метаданные
r

Глава 1. Философия .NET 53

Замечание. Относительно сокращения "IL" здесь уместно сказать несколько дополнительных слов.
В ходе разработки .NET Официальным названием для IL было Мiсrоsоft
lintermediate Language
(MSIL). Однако в вышедшей версии .NET зто название было изменено на CIL (Соттоп
Intermediate Language - общий промежуточный язык). Позтому вам следует знать, что в публи­
кациях, посвященных .NEТ, сокращения IL, MSIL и CIL обозначают одно и то же. В соответствии
с терминологией, принятой сегодня, в тексте зтой книги используется сокращение CIL.

После создания * .dll или * .ехе с помощью подходящего .NЕТ-компилятора, со­


ответствующий модУЛЬ упаковывается в JCOМ1Wновочный блоlC. Подробное описание
компоновочных блоков .NEТ име~тся в главе 11. Однако, чтобы продолжить наше
обсуждение среды выполнения .NEТ, вы должны знать основные особенности фор­
мата этих новых файлов.
Как уже было сказано, компоновочный блок содержит программный код CIL,
который концептуально напоминает байт-код Java в том смысле, что он не КОМПИ­
лируется в специфические для соответствующей платформы инструкции, пока это
не станет абсолютно необходимо. Обычно "абсолютная необходимость" означает
момент, когда на какой-то блок СIL-инструкций (например, реализацию метода)
выполняется ссылка для его использования в среде выполнения .NEт.
В добавление к СIL-инструкциям, компоновочные блоки также содержат мета­
данные, которые подробно описывают особенности каждого "типа" внутри данной
бинарной .NЕТ-единицы. Например, если вы имеете класс с именем SportsCar,
соответствующие метаданные типа будУТ описывать такие злементы, как базо­
вый класс SportsCar и интерфейсы, реализуемые SportsCar (если таковые име­
ются), а также содержать полные описания всех членов, поддерживаемых типом
SportsCar.
Метаданные .NEТ более совершенны по сравнению с метаданными СОМ. Вы,
возможно, уже знаете, что бинарные СОМ-объекты обычно описываются с помо­
щью библиотеки ассоциированных типов, а это почти то же самое, что и бинарная
версия IDL-кода (Interface Definition Language - язык определения интерфейса).
Проблема использования СОМ-информации в том, что зта информация не обяза­
тельна, и IDL- код не может документировать внешние серверы, которые нужны
для правильного функционирования данного СОМ-сервера. В противоположность
этому метаданные .NEТ присутствуют обязательно и автоматически генерируются
соответствующим .NЕТ-компилятором.
Наконец, в добавление к CIL и метаданным типов, сами компоновочные блоки
также описываются с помощью метаданных, для которых используют специаль­

ное называние манифест (manifest). Манифест содержит информацию о текущей


версии компоновочного блока, информацию о "культуре" (используемую для лока­
лизации строк и графических ресурсов) и список всех ссылок на внешние компо­
новочные блоки, которые требуются для правилъного функционирования. Из сле­
дующих глав вы узнаете о различных инструментах, которые MOryт использоваться

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


манифеста.
54 Часть 1. Общие сведения о языке С# и платформе .NET

Одномодульные и многомодульные
компоновочные блоки
Во многих случаях компоновочные блоки .NEТ- это просто файлы двоичного
кода (*.dll или *.ехе). Поэтому. если вы строите *.dll .NEт, можно считать. что
файл двоичного кода и компоновочный блок - это одно и то же. Точно также. если
вы строите выполняемое приложение для настольной системы. файл *.ехе тоже
можно считать компоновочным блоком. Но из главы 11 вы узнаете. что указанное
соответствие не столь однозначно. Строго говоря. если компоновочный блок со­
стоит из одного модуля *.dll или *.ехе. вы имеете одно.модульныЙ комтwновочный
блок. Одномодульный компоновочный блок содержит весь необходимый код CIL.
метаданные и манифест в одном автономном отдельном пакете.
Много.модульные JCOмтwновочн.ые блоlCU, в свою очередь. складываются из мно­
жества бинарных .NЕТ-единиц. каждая из которых называется .модулем. При зтом
один из таких модулей (он называется первuчнbIМ модулем) должен содержать
манифест компоновочного блока (и может содержать также СIL-инструкции и ме­
таданные различных типов). Остальные связанные модули содержат манифест
уровня модуля. CIL и метаданные типов. как вы можете догадаться. в манифесте
первичного модуля компоновочного блока документируется набор необходимых
"второстепенныхМ модулей.
Но зачем создавать многомодульные компоновочные блоки? Когда вы делите
компоновочный блок на отдельные модули. вы получаете более гибкие возможно­
сти инсталляции. Например. если пользователь ссылается на удаленный компоно­
вочный блок. то среда выполнения загрузит на его машину только необходимые
модули. Поэтому вы можете сконструировать свой компоновочный блок так. чтобы
редко используемые типы (например. HardDriveReforrnatter) были выделены в от­
дельный автономный модуль.
Если все ваши типы размещаются в компоновочном блоке. представляющем
собой единый файл. конечному пользователю придется загружать большой набор
данных. из которых в действительности могут понадобиться далеко не все (а зто.
очевидно. означает лишнюю трату времени). Итак. компоновочный блок на самом
деле логически сгруnтшpoван. в один или несколько модулей . которые должны ин­
сталлироваться и использоваться. как единое целое.

Роль CIL
Теперь. когда вы имеете начальное представление о компоновочных блоках
.NET. давайте немного подробнее обсудим роль общего промежуточного языка
(CIL). CIL- это язык. находящийся выше любого набора инструкций. специфиче­
ского для конкретной платформы. Независимо от того. какой язык .NEТ вы вы­
берете для использования. соответствующий компилятор сгенерирует инструкции
CIL. Например. следующий npогрaмМНblЙ код С# моделирует тривиальный кальку­
лятор. Не пытаясь пока что полностью понять синтаксис этого примера. обратите
внимание на формат метода Add() в классе Calc.
r
,
I

Глава 1. Философия .NET 55


/ / Саlс.СВ
using System;

паmезрасе CalculatorExample
(
/ / Этот JCJIacc содержит точку входа DpИJIо.еНИJl.
public class CalcApp
(
static void Main()
(
Calc с = new Calc();
int апз = c.Add(10, 84);
Console.WriteLine("10 + 84 is {О}.", апз);

/ / Ждать, по ха ПOJJъsоааТ8J18 не на.мет JCJIааиury ввода.


Console.ReadLine();
// C'-хanъКУЛRТОР·
public class Calc
(
public int Add(int х, int у)
( return х + у; )

После того как компилятор С# (сзс.ехе) скомпилирует этот файл исходного


кода. вы получите состоящий из одного файла компоновочный блок *.ехе. кото­
рый содержит манифест. СIL-инструкции и метаданные . описывающие каждый
аспект классов Calc и CalcApp. Например. если вы откроете этот компоновочный
блок с помощью ildasm.exe (мы рассмотрим ildasm.exe немного позже в этой же
главе). вы увидите. что метод Add () в терминах CIL представляется так .

. method public hidebysig instance int32 Add(int32 х, intЭ2 у) cil managed


(
11 Code size 8 (Ох8)
.maxstack 2
.locals init ([О] int32 CS$l$OOOO)
IL_OOOO: ldarg.1
IL 0001: 1darg.2
IL 0002: add
IL 0003: stloc.O
IL 0004: br.s IL 0006
IL 0006: ldloc.O
IL 0007: ret
11 end of method Calc: :Add
Не беспокойтесь. если вы пока не в состоянии понять СIL-код для этого мето­
да- в главе 15 будут описаны основы языка программирования CIL. Здесь следует
сконцентрироваться на том. что компилятор С# генерирует СIL-код. а не специфи­
ческие для платформы инструкции.
Напомним теперь. что это верно для всех .NEТ-компиляторов. для иллюстрации
предположим. что вы создали аналогичное приложение с помощью Visual Basic
.NEТ (vв .NEТ). а не с помощью С#.
56 Часть 1. Общие сведения о языке С# и плаТформе .NET

, Calc.vb
1mports System
Namespace CalculatorExample
, VВ • пт 'Модуn.' - ато JCЗIасс, содер.ащий тоn.ко
, статические ЧJlенw.
Module CalcApp
Sub Main ()
Dim ans Аэ 1nteger
Dim с Аэ New Calc
ans = c.Add(10, 84)
Console.WriteLine("10 + 84 is (О}.", ans)
Console.ReadLine()
End Sub
End Module
Class Calc
Public Function Add(ByVal х Аэ 1nteger, ByVal у Аэ 1nteger) Аэ 1nteger
Return х + у
End Function
End Class
End Namespace
Если теперь проверить СIL-код для метода Add ( ) , вы обнаружите подобные ин­
струкции (слегка Мподправленные" компилятором vв .NEТ) .

. method public instance int32 Add(int3 2 х, int32 у) cil managed


{
/ / Code size 9 (Ох9)
.maxstack 2
.locals init ([О] int32 Add)
1L 0000: пор
1L 0001: ldarg.1
IL 0002: ldarg. 2
1L 0003: add. ovf
1L 0004: stloc.O
1L 0005: br.s 1L 0007
IL 0007: ldloc. О
1L 0008: ret
} / / end of method Calc: :Add

Преимущества CIL
Вы можете спросить, зачем компилировать исходный код в CIL, а не прямо в
набор специальных системных команд. Одним из преимуществ этого является ин­
теграция языков, поскольку вы уже убедились, что все компиляторы .NEТ выда­
ют приблизительно одинаковые наборы CIL-инстрУКЦИЙ . Поэтому все языки MOryт
взаимодействовать в рамках четко обозначенной двоичной Марены".
Кроме того, поскольку CIL демонстрирует независимость от платформы, каркас
.NEТ Framework тоже оказывается независимым от платформы, обеспечивал то, к
чему так привыкли разработчики J ava (единую базу программного кода. способно­
го работать во многих операционных системах). Фактически уже имеется между-
r
Глава 1. Философия .NET 57
народный стандарт для языка С#, а значительная часть платформы .NEТ реализо­
вана для множества операционных систем, отличных от Windows (более подробная
информация об этом имеется в конце главы). Но, в отличие от Java, .NEТ позволяет
строить приложения, используя язык вашего предпочтения.

Преобразование CIL-КОАа в набор инструкций,


соответствующих платформе
ВвидУ того, что компоновочные блоки содержат СIL-инструкции, а не инструк­
ции для конкретной платформы, программный код CIL перед использованием
приходится в фоновом режиме компилировать. Объект, который компилирует
программный код CIL в инструкции, понятные процессору машины, называется
JfГ-ICОМ11ШlЯmoром Uust-in-time - точно к нужному моменту), который иногда М по _
дружески" также называют Jitter. Среда выполнения .NEТ использует JIТ-компи­
лятор, соответствующий конкретному процессору и оптимизированный ДЛЯ соот­
ветствующей платформы.
Например, если ваше .NЕТ-приложение предназначено для выполнения на
MKoмnaктHoM" устройстве (таком, как, например, КПК), то соответствующий JIT-
компилятор будет иметь специальные средства для учета условий ограниченности
памяти. Если это компоновочный блок для сервер ной системы (где объем памяти
редко оказывается проблемой), то соответствующий JIТ-комnилятор будет оптими­
зирован ДЛЯ работы в условиях достаточного объема памяти. Таким образом раз­
работчики получают возможность создавать только один блок npограммного кода,
который с помощью JIТ-комnиляции можно выполнять на машинах с разной ар­
хитектурой.
К тому же, при компиляции СIL-инструкций В соответствующий машинный код
JIТ-комnилятор поместит результаты компиляции в кзш В соответствии с тем, как
зтого требует соответствующая операционная система. Так, при первом вызове
метода с именем PrintDocument() соответствующие СIL-инструкции комnилиру­
ются В конкретные инструкции платформы и сохраняются в памяти для использо­
вания в дальнейшем. Позтому при следующих вызовах PrintDocument () необхо­
димости в повторной компиляции CIL не возникает.

Роль метаданных типов .NET


Кроме СIL-инструкций , компоновочный блок . NEТ содержит исчерпывающие
и точные метаданные, описывающие все его типы (классы, структуры, перечни и
т.д.), определенные в бинарном объекте, и все члены каждого типа (свойства, ме­
ТОДЫ, события и т.д.). К счастью, задача создания метаданных всегда возлагается
на компилятор (а не на программиста). По причине того, что метаданные .NEТ так
подробны и точны, компоновочные блоки оказываются единицами, способными
себя полностью описать, - настолько полно, что для бинарных .NЕТ-объектов не
возникает необходимости регистрироваться в реестре системы.
Для иллюстрации формата метаданных типов .NET давайте рассмотрим ме­
таданные, сгенерированные для метода Add () С#-класса Calc, представленного
выше (метаданные, генерируемые для VВ .NЕТ-версии метода Add () , оказываются
аналогичными).
58 Часть 1. Общие сведения о языке С# и ппатформе .NET

TypeDef #2 (02000003)

TypDefName: CalculatorExample.Calc (02000003)


Flags : [Public] [AutoLayout] [Class]
[Ansi Class] [BeforeFieldInit] (00100001)
Extends : 01000001 [TypeRef] System.Object
Method #1 (06000003)

MethodName: Add (06000003)


Flags : [Public] [HideBySig] [ReuseSlot] (00000086)
RVA : ОхООО02090
ImplFlags : [IL] [Managed] (00000000)
CallCnvntn: [DEFAULT]
hasThis
ReturnType: 14
2 Arguшents
Argument #1: 14
Argument #2: 14
2 Раrашеtеrs
(1) ParamToken : (08000001) Name : х flags: [попе] (00000000)
(2) ParamToken : (08000002) Name : у f1ags: [попе] (00000000)

Метаданные используются средой выполнения .NEТ, а также различными сред­


ствами разработки. Например, возможность IntelliSense, предлагаемая в Visual
Studio 2005 в режиме проектирования, основана на чтении метаданных компоно­
вочного блока. Метаданные используются различными утилитами просмотра объ­
ектов, инструментами отладки и самим компилятором С#. Для полноты картины
заметим также, что использование метаданных лежит в основе множества .NEТ­
технологий, включая удаленный доступ, отображение типов, динамическое связы­
вание, Web-сервисы XМL и сериализацию объектов.

Роль манифеста компоновочного блока


Наконец вспомним, что компоновочный блок .NEТ содержит также метаданные,
описывающие сам компоновочный блок (зти метаданные называются манифест).
Среди всего прочего, в манифесте документируются все внешние компоновочные
блоки, которые требуются текущему компоновочному блоку для корректного функ­
ционирования, указан номер версии компоновочного блока, информация об автор­
ских правах и т.д. Подобно метаданным типов, генерирование манифеста компо­
новочного блока тоже является задачей компилятора. Вот некоторые подходящие
для иллюстрации элементы манифеста CSharpCalculator.exe .
. assembly extern mscorlib
{
.publickeytoken = (В7 7А 5С 56 19 34 ЕО 89 )
. ver 2: О : О : О

.assembly CSharpCa1culator
{
r

Глава 1. Философия .NET 59


.hash algorithm ОхООО08004
.ver 0:0:0:0

.modu1e CSharpCalcu1ator.exe
.imagebase ОхО0400000
.subsystem ОхОООООООЗ
.fi1e a1ignment 512
.corf1ags ОхОООООООl
По сути, этот манифест содержит указания на внешние компоновочные бло­
ки, необходимые для CSharpCa1culator.exe (для этого используется директива
.assembly extern), а также различные характеристики самого компоновочного
блока (номер версии, имя модуля и т.д.).

Общая система типов


Компоновочный блок может содержать moбoе число четко определенных "типов".
В мире .NEТ "тип" - зто просто общий термин, используемый для обозначения лю­
бого злемента из множества (lCЛQCс, cтpyкmypa. uн.meрфеЙС, neречен.ь, делегam}.
При построении решений с помощью любого языка .NEТ вы, скорее всего, будете
взаимодействовать с каждым из этих типов. Например, компоновочный блок мо­
жет определять один класс, в котором реализовано ряд интерфейсов. И, возможно,
ОДИН из методов интерфейса будет принимать перечень в качестве входного пара­
метра, а возвращать некоторую структуру.

Напомним, что crs (общая система тшIOВ) - это формальное описание того, как
должны определяться типы, подходящие для использования в среде CLR. Обычно
внутренние механизмы CТS важны только тем, кто создает средства разработки
и/или строит компиляторы для платформы .NEТ. Но для любого программиста
.NEТ важно знать, как работать с пятью типами, определяемыми спецификациями
CТS для выбранного разработчиком языка программирования. Ниже предлагается
краткий обзор соответствующих вопросов.

Тип класса
Любой язык, совместимый с .NEТ, поддерживает, как минимум, тип к:ласса. ко­
торый является "краеугольным камнем" объектно-ориентированного программи­
рования (ООП). Класс может состоять из любого числа членов (таких, как свойства,
методы и события) и элементов данных (таких, как поля). В С# классы объявляют­
ся с помощью ключевого слова class.
// тип к.nacca Cjf.
public c1ass Calc
{
public int Add(int х, int у)
{ return х + у; }

Процесс построения типов класса crs в С# будет рассматриваться в главе 4, но


ряд общих характеристик типов класса приводится в табл . 1.2.
60 Часть 1. Общие сведения о языке С# и ппатформе . NEТ

Таблица 1.2. Характеристики классов CTS

Характеристика класса Описание

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


классов, Т.е. не позволяют наследование

Наличие интерфейсов Интерфейс - это набор абстрактных членов, обеспечивающих


взаимодействие между объектом и пользователем этого объекта.
Спецификации CTS не ограничивают число интерфейсов, реализу­
емых в рамках класса

Абстрактность или Абстрактные классы не позволяют неnoсредственное сознание их


конкретность экземпляров - они предназначены для определения общих эле­
ментов поведения производных типов. Конкретные классы могут
быть созданы непосредственно

Видимость Каждый класс должен иметь атрибут видимости (visibility). По сути,


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

блока (как, например, при ватный класс справки)

Тип структуры
Понятие структуры в CТS также формализовано. Если вы знаете С, вам будет
приятно узнать, что зти пользовательские типы "выжили" и в мире .NEТ (хотя вну­
тренне они ведут себя немного по-иному). Упрощенно говоря, структура- это
"облегченный" тип класса с семантикой на базе значений. Более подробная инфор­
мация о структурах предлагается в главе 3. Обычно структуры лучше всего под­
ходят для моделирования геометрических и математических данных, и в С# для
создания структур используется ключевое слово s t r u с t.

// тип струхтуры ct.


struct Point

/ / Струхтуры ио:ry'l' содер.атlo ПОnR.


public int xPos, yPos;

/ / Струхтуры ио:ry'l' содер.атlo паракеТРИSО8aннuе ХОИСТРУХ'l'орu.


public Point(int х, int у) ( xPos = х; yPos = у;}

/ / СтрухтypiI иоЖ'У'1' определR'l'1o ие'l'ОДЫ.


public void Display()
(
Console.WriteLine("«(O}, (l}", xPos, yPos);
r
Глава 1. Философия .NET 61

Тип интерфейса
Инmeрфейс- это именованная коллекция определений абстрактных членов,
которая может поддерживаться (т.е. реализовьmаться) данным классом или струн­
турой. В отличие от модели СОМ, интерфейсы .NEТ не являются производными
одного общего базового интерфейса, такого как IUnknown. В С# типы интерфейса
определяются с помощью ключевого слова interface, например:
// тип ИИ'1'8рфейса С*.
public interface IDraw
(
void Draw () ;

Сами по себе интерфейсы не очень полезны. Однако, когда класс или струн­
тура реализуют данный интерфейс своим собственным уникальным образом, вы
можете запросить доступ к соответствующим функциональным возможностям, ис­
пользуя ссылку на интерфейс в полиморфной форме. Программирование на базе
интерфейсов будет рассматриваться в главе 7.

Тип перечня
Перечень - зто удобная программная конструкция, в которой группируют­
ся пары Нимя-значение". Предположим, вы создаете видеоигру, в которой игроку
позволяется выбрать персонажа в одной из трех категорий: Wizard (маг), Fighter
(воин) или Тhief (мошенник) . Вместо того чтобы использовать и отслеживать чис­
ловые значения, соответствующие каждой из возможностей, вы можете построить
перечень, используя для этоro ключевое слово епиm.

// тип пер8ЧИR С*.


public епиm CharacterType
{
Wizard = 100,
Fighter = 200,
Thief = 300

По умолчанию для каждого зле мента выделяется блок памяти, соответствую ­


щий 32-битовому целому, но при необходимости зто значение можно изменить
(например, в случае программирования для устройств с малыми объемами памя­
ти, таких как КПК). Спецификации crs предполагают, что типы перечня должны
·получаться" из общего базового класса, System.Enum. Из главы 3 вы узнаете, что
этот базовый класс определяет ряд весьма полезных членов, которые позволяют
программно извлекать, обрабатывать и преобразовывать соответствующие пары
·имя-значение" .
62 Часть 1. Общие сведения о языке С# и платформе .NET

Тип делегата
Делегат- это .NЕТ-эквивалент обеспечивающих типовую безопасность ука­
зателей ФУНКЦИЙ С. IЛавное отличие заключается в том, что делегат .NEТ - это
класс, получаемый путем наследования System.MulticastDelegate. а не просто
указатель на КОНIqJетный адрес в памяти. В С# делегаты объявляются с помощью
ключевого слова delegate.
/ / Э'JIо'1' '1'ИD де.пеrа'1'а С# lIO.е'1' I yxuыaa'l'J. I на .moбоЙ ме'1'ОД, воsвращаl:lЩPlЙ
/ / цепое значение и ао.пуч8.DЦИЙ на вход два Ц8.1JIIX sначеИИJI.
public delegate int BinaryOp(int х, int у};

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


вызова другому злементу. что создает основу для архцтектуры обрабOТI<И событий
.NEТ. В главах 8 и 14 будет ПОJ(aзано, что делегаты имеют внутреннюю поддержку
методов многоадресного (предназначенного для множества получателей) и асин­
хронного выэова.

Члены типов
Теперь после рассмотрения всех типов, имеющих формальное определение в
CТS. вы должны осознать, что большинство типов может иметь любое число чле·
нов. Формально член тиna- зто любой элемент множества IlCонструlCmoр, де­
cm.РУlCmoр (flnal1zer), сmaтичесrcuй lCoнcmpylCmop. ВJWженный тип, операция. ,ме­
moд. cвoйcm.вo. uндelCcamop. rwле. rwле толысо для чmeнuя, lCонсmшuna, событие}.
Специфю<ации CТS определяют различные ~характеристю<и", которые могут
связываться с данным членом. Например. каждый член имеет признак. характе­
ризующий его доступность (открытый, частный. защищенный и т.д.). Некоторые
члены могут объявляться как абстрактные. чтобы навязать полиморфное поведе­
ние производным типам. или виртуальные. чтобы определить фиксированную (но
допускающую замену) реализацию. Бо,IIЬшинство членов может обозначаться как
статические (~привязанные" к уровню класса) или как члены зкземпляра (~привя­
ззнные" к уровню объекта). Конструкция членов типа будет подробно обсуждаться
в следующих главах.

Замечание. Как будет показано в главе 10. в .NEТ 2.0 подцерживается конструкция обобщенных
типов и обобщаннbIX членов.

Встроенные типы данных CTS


Еще одной особенностью CТS. о которой следует знать. является то. что специ­
фикации CТS определяют четкий набор базовых типов данных. Хотя каждый язык
обычно предлагает свое уникальное ключевое слово. используемое для объявления
конкретного встроенного типа данных CТS. все эти ключевые слова в конечном
счете приводят к соответствующему типу. определенному в компоновочном блоке
mscorlib.dl1. Взгляните на табл. 1.3. предлагающую информацию о том. как ба­
зовые типы данных CТS выражены в разных языках .NEТ.
r
Глава 1. ФИЛО~ОфИR .NET 63
Та6nмца 1.3. 'Встроенные типы дaHNblX CTS
Тип Д8ммых CТS КnIO"teIlO8 cna~ КIuo'Ieloe CnО8О Кrooчееое СnО80
VВ.NEТ С# Managed Sxtens1on. for С4-+
System.вyteByte Byte byte un.зi gned char
Вуэtеm.$ВytеSВуtе SВyte sbyte siqned e:har
System... Lntiб $hort short shlDrt
System.Int32 Integer iцt int ~nИ lOrJ,g
3"уs'tеm.Iпtб4 Ьоnч ~Clng int64
Sуstсеm.1Ппt16 OShort usЪо~t Un8igned s ·h az;t
sузtещ, Ulnt32 UInteger uiht uDsigl1ed 'i.nt "ИЛИ
uns,i gned long
System, UIпtб4 ULong ulOJlg \.lnзigпеd ~int64

Syste1!l~$ingleSingle Single float Float


Sys te1Il. Do,'lbl,eDouble Double dOl.lble Douыle

Syst.em.Qbjel::tO.bjeet Object obje,ct Object~

System.CharChar СЬат сЬа:: wdllar t


System.Stringstring S-tri n 9 S.tring 'Stririg~

,S Y5tem.DeeiIl)alDecimal Decimal decima;l DeQimal


System.Boolea.nВooJ,ea,n Boolean bool Воо1

Общеязыковые спецификации
Вы. конечно, <!Баете, что разные JIзыкiI программироlЩRИ.R вьq>3Жаю'I: ОДНИ и
те же прогрa.м:мm,tf: 1СВfICТPYlЩJm в своих уникальных терминах. НanРJIМс:р. в С#
кониаrreнaцJoШ строкобознач:ается ЗНaItOМ "плюс" (+}. а Ц' VВ .NE;Т для этого исполь­
~eтca. aЫlТepcaнд.[ ~) , даже 'J'O.I."Aa. кorдa.двa язша ВЫраж81Q"Г одну и ту _ :пpoi'JЖМ­
ЩI}'Ю' цдиому (JiЩIpимер, функЦИю, не возйрзщшо1ЦYJCl.lQП\aКОro знач~), весьма
вероятно ТО, ч';ГО при атом ИСПOJlьэуется pagт.m сиmаксис.

, Нв .озара . .-.di .....e~ ~OД vв .. _.


l?\J.blic Sub MyMethod ( )
I Ие1СO'rOpJiIЙ Dp01"раМКDIЙ ход • .•
End ЗиЬ

/I IJe воsвреща---* ~~ 11i1l1'oA ct.


publ i c voidMyMethod()
I
/ !ИВJЮlllорЩ tgi)0Ж'р8МJПIМЙJtо;ц • ••

Вы уЖе mщели. ЧТО эти небодыпве отличиа в синтаксисе весуществеНШiI с


точки зрения среды вьnroЛНeflЩl ,NEf, досколыо/ соответствующие компиляторы
(BдaннriM случае это ,,"bC.e~e и е:.3, с.ехfЗ) rенерирJ1DТ аналог.ичвые множества CJL..
инструкЦИЙ. Но язъпm моryт-таюке отЛИ'Щт~я по фyншuIOналы-IOСТК. КоIOq>етНblЙ
язык .NEГ может. И'anpим:ер. иметь Ю1Ючево~ слово или не имeтr. eto J1iПSI npeACТaв-
64 Часть 1. Общие сведения о языке С# и платформе . NEТ

ть или не подцерживать ТИПЫ указате­


ления д81fных без знака. может подцержива
необходимо иметь базовый уровень,
ля. С учетом таких вариаций возможностей
подцержкой .NEт.
которому соответствовали бы все языки с
Спецификации CLS (Соттоп Langtщgе Speci
ficatl on - общеязьшовые специфи­
подробностях описывают минималь­
кации) - это набор правил. которые во всех
рые должен подцерживать данный
ное и полное множество возможностей, кото
ный код. подх:одЯIЩIЙ для CLR. и
.NET-коМI1ИЛЯТОР. чтобы генерировать программ
для всех язьшов. предназначенных для
в то же время быть одинаково доступным
можно рассматривать, как noдMНO­
платформы .NEт. Во многих отношениях CLS
жностей. определенного в рамках
жеcmвo полного набора функциональных возмо
crs.
счете набором правил. которых долж­
CLS являются в конечном
Спецификации
ра, если они собираются создать npOД}'RT,
ны придерживаться создатели КОМIIИЛЯто
"незаметно" для пользователя . Каждое
который во "вселенной .NEТ функционирует
М

правило имеет простое имя (например, UПрав


ило CLS номер и описывает. какое 61
тем, кто fCaRим-то
тем. кто создает компиляторы, и
отношение это правило имеет к
цией CLS является могущественное
образом взаимодействует с ними. Квинтэссен
npaвШlO 1.
• Правшro 1. Правила CLS применяютел только к тем компонентам типа. кото­
новочного
елами определяющего их компо
рые открыты для доступа за пред

блока.

ть (правильное) заключение. что все


с учетом этого правила вы можете Сдела
используемой для внутреннего устрой­
остальные правила CLS не касаются логики.
которые должны согласовываться с
ства типа .NEт. Единственные аспекты типа,
параметры и воз­
CLS, - это определения членов (т.е. соглашения о выборе имен,
етного члена может использовать лю­
вращаемые типы). Логшm реализации конкр
только это будет скрыто от Uвнешнего
бые несогласованные с CLS технологии. если
мира".
согласованным справилами CLS. по­
Так. следующий метод Add () не является
значений используются данные без зна­
скольку для параметров и возвращаемых
ка, которые в CLS не указаны.

publ i c class Calc


(
11 Э'1'И o'l'кpW'1'll8 Д8.JIНWB без знака не cozoJlacyJD'l'cSI с CLS!
publi c ulonq Add( ulonq х, ulonq у)
{ rеturл х + у;}

только внутри типа, как указано


Но если вы используете данные без знака
ниже

publ i c c lass Calc


(
publ ic int Add( int х, int у)
{
KO внутри '1'ИП&,
11 Здесъ пвреllени&Sl ulonq иcno.n.вуе'l'СSl 'l'OJIЪ
11 ПОЗIrОИУ nP_ИJlа CLS не HapYlQJll'l'CSl.
ulong t e mp;
Глава 1. ФИЛОСОфИЯ ,NEТ 65
ret1;irn х + у;

то правила СLЭ остаются выполнен~. и вы может~ быть уверены. что теперь


любой язьnc.NЕТ CMO,m€'l' BЫ3Ba~ метод Ad.d () .
Коцечцо, J\'PQмe правица 1 в CtS опре;целен;о много дрyr-и.х npащ1Л. Нацример. в
CLS ОIЩQЫВЗ.e'l"СЯ. ЩIl{ ЯЗЫR доЛ"лtен npeдставлять строки текста. пере'-п-m. статяче­
СИпе' чледы и т.д. К с'qастью, со;всем не обязателыfo запоминать 13ce &т1i npавилд,
чтобы отать :искJ'сцbI)\{ разработчцом .NEТ, Снова повторm.J. что r.JIY6oKoe и полное
ш:щимаииеспецифИI<aЦИЙ CТS 'и CLS необходимо TO;JJЪRO соаца.тeщц.t соответствую~
:щих ннС'Тр~еитов разрабоТЮl и КОМIIИЛЯторов.

Гарантия СLS~совместимости
}(.ан вы уанаете из теЕста ЭТОЙ IGщrи. В с.# и;меетс:я PJIд rrpoграммнЪ1Х ксщструк­
ций. которые 'Не явJШЮтся CLS-G:о:вмеcтщ.fblМИ. ОднаIW хороlIIИ\l!I известием явШl­
е'ГСЯ '1'9. что BJ:d можете заставить компилятор С# вьmол::н.ятъ проверку вашегО' дро­
грам:много JЮда На соответствие CLS, ИСПOJrьзуя ,!J,IЩ9ТОГО QДИН атрибут.NEI'.

11 УХа.аавиiet 1I:омrlИil1Ji1'Z'ОРУ С. InШOnнw.tЪ проверху ка соО_В'Z'C'PJIИe CLS.


Lassambly; .sуjtеrn.СL5сФnрliаnt (цце} ]

В главе 12 будут расс-мотрецьу ТОНJI!()СТЦ программировщ·щ:я аа oe'ЦOB~ 0СПРдЬ­


зования атрибутов, Пока QTO важ:но просто ПОПЯТЬ, что атрибут 1СLSСQщрliantJ
дает IЮМШ'l",ЩlТОрУ С# YJЩзmще провеРЛTh :ка.ждую строцу ПРОГРШifМВQr0.кода На со­
OТ!i1етствие npавилЩ{ CLS. Если обнаружится Нарynrtщде прав~ СLЭ. вы Щ)дrIQ:те
соо(}щение об опmбне 1I10.мщmяциn и оnиcанде ~еIюрреRТНШ'О проrр8МJ'dНОГО кода.

Общеязыковая среда выполнения


в дополнениекспецифишщинм cтs и CLS. IIOCЛедней 1la данныЙ мамеш аб­
бревиатурой, которую мы расtmотрим, будет аббревиатура CLR (СОПllпоп Langиage.
Run.time - оБIЦeЯэblRОВая среда ВlJl'полнеmm:). ДI1я про:tраммированив. термин сре­
да выlIoлненuя можно Пониматъ. шш набор внеtrni"ИХ tерви:сов. необходимых ДЛJI
вьmа.illiеR'ип данной о:компил:ировaIIНОЙ едиmщы прогрaммJiога Кода. Нвпример.
IЮгда разработчmt при создании ПОВОГQ ПРИ.!Iоже1-htя использует библиотеку базо­
вых ltJJacCQ» Microsoft (MFC). шtзнает. ЧТО дгт ВЫШJlШения етО про:граммы потре­
буется СОOlI'Вeтствующий iJЫПОЛНЯ€МЫIЙ :МOдYJГЬ библиотеки MFC (т.е. П\Zс42.dll).
Другие популярные ЯЗ-Jill(И также n"pедлагают соотвеТС"ГВуЮщие ВЪШОЛНЯ€М1iIе мо­
дУЛИ. Прогр.аммисты VВ6 привяза~гы :к одному или двум ВI:;ШОШlяемым МОдУлям
(например. msvЬvmбо.dl1). РазрабоГlИНИ Java ПРИВЯЗallЫR виртуальной машине
Java (JVМ) и 'i:д.
Платформа .NE:Тпредлагает совсем .црyrоЙ ПfJШЩИI1 орТa1llиaдJm среды Bыno.iI­
I-reюIЯ. Ра3l-Iица меж,пу средой выполнения .NEТ и средой выполнеяин, о :fСОТОРОЙ
roворИЛОСь BblII1e. эакшочаетсн в том. что сре,па вьmОJlнения .NEТ обеспечивает
единый u вполне onpеделею·JЫЙ "слой" выполненин. общй:й для всех язьncов И rmат­
форм~ совместимых G .NEТ.
66 Часть 1. Общие сведения о языке С# и плаТформе .NET
ваемой
ОСНОВНОЙ механизм физически заключается в библиотеке. назы
CLR
msco ree.d ll (известной также под названием Соmmоп
Objec t Runti me Ехесutlоп
на компоновоч­
Eng1ne - общий объектный модуль механизма вьmолнения). Когда
ный блок ссылаются для использования. rosco
ree.d ll автоматически загружается
уемый компоновочный блок. Механизм
и. в свою очередь. зarружает в память треб
Прежде всего. и это самое главное. за
выполнения отвечает за целый ряд задач.
го блока и нахождение запрашиваемо­
выяснение расположения компоновочно
я содержащихся там метаданных.
го типа в бинарном объекте с помощью чтени
преобразует СIL-код в соответствующие
Затем среда CLR размещает тип в памяти.
ходимые проверки безопасности. а за­
платформе инструкции. выполняет все необ
тем выполняет полученный программный код.
оновочных блоков и СОЗДaJlllЮ поль­
Вдобавок к зarруэке созданных вами комп
одимо. взаимодействует с типами.
зователъсК1Dt типов. CLR также. если это необх
ов .NEт. Хотя вся библиотека базо­
содержaIЦИМ"СЯ в библиотеках базовых класс
компоновочных блоков. ·ключевым"
вых классов разбита на целый ряд отдельных
компоновочным блоком является msc orlib
.dll. Фай.'l msc orlib .dll содержит
ют в себе решеция широкоro спектра
множество базовых типов. которые объединя
ые типы данных. используемьzе все­
оБIЦИX задач программирования. а также базов
жеНИЙ вы автоматически получаете
ми языками .NEт. При построении .NET-прило
ному блоку.
доступ к этому специальному компоновоч
икающих мещцу вaI1IИМ исходным ко­
На рис. 1.3 показана система связей. возн
базовых классов) ..NEТ-ком.пилятором и
дом (использующим типы из библиотеки
механизмом выполнения .NEт.

Различия между компоновочными блоками,


пространствами имен и типами
отек программного кода. Цель библи­
каждый из нас понимает важность библи
разработчику готовый набор блоков
отек. таких как MFC. J2EE или AТL. - дать
о строить но­
го кода. опираясь на которые можн
уже существующего программно
библиотек с программным кодом для
вые приложения. Но язык С# не предлarает
использовать .NEТ-библиотеки. ней­
конкретного языка. Разработ'lИКИ С# могут
чтобы все типы в библиотеках базовых
тральные в языковом отношении. для того
форма .NEТ предлarает использовать
классов были правильно организованы. плат
понятие пространства имен.
тся группой связанных типов. содер­
Упрощенно roворя. пространство имен являе
пространство имен Syste m.IO содер­
жaIЦИXСЯ в компоновочном блоке. Например.
-вывода. npостранство имен Syste m.Da ta
жит типы. связанные с операциями ввода
базами данных и т.д. Важно понимать.
определяет основные типы ДЛЯ работы с
что один компоновочный блок (такой как. напри
мер. msco rlib. dll) может содер­
ое из которых может. в свою очередь.
жать любое число пространств имен. кажд
содержать любое число типов.
на рис. 1.4. на котором показан
Чтобы СИ'1Уация стала более ясной. взгляните
снимок окна Objec t Broweг иЗ Visua1 Studi o
2005. Этот инструмент позволяет видеть
текущий проект. пространства имен.
ко:мпоновочные блоки. на которые ссылается
существующие в пределах данного
содержащиеся в компоновочных блоках. типы.
го типа.
пространства имен. и члены каждо
r
Главе 1. Философия .NП 67
Обратитевнимamte нато. что mscorlib.dll содержит очень МНОГО самы:х раз­
ных npоtтранствИМен. и в кащдОМ из этих простршю:rв имев содержатся свои се­
МЭ1IТичеC1i.И СIШзанные ТИШ:il.

ОСНОВНЫМ отличием этого подхода от TВJWX э.ависящих ОТ I«!НR'peТВOJ'Q Я3Ъrna


библиотек, как MFC. НВJ.яется 'f'O, что ~ рЩ-лътате все .8ЗьШи, поддерживаемые В
среде въпroлнеНИR .NE1: используют оо/-ш U те же npостранC"I'Вa имен и одН:и и те
жетиnы:.

И~ДI'IЫЙ кeд.NET
f\a базе
любого яэыl!t:t .NEТ

I<oМПОНOlOЧНЫЙ блок
",dllили ·.ехе
(СIL:-щ М8ЩQaНные и r.taНИфecL)

_UН,IQ.- 8.bJ.IIOIIII8IW1.НEТ
(mscoree.dll)

Бкблм.от,кИ
базовых кnaCc08

(inSфl'IiЬ;dll и др.)

Рис. 1.3. Мрдуль mscоrее.dП в д&йствии


68 Часть 1. Общие сведения о языке С# и платформе .NET

Рис. 1.4. Один компоновочный блок может содержать любое количество пространств имен

Для иллюстрации рассмотрим следующие три программы. представляющие


вариации вездесущего примера "Неllо World" соответственно на С#. vв .NET и
Managed Extensions for С++.

11 He1.10 wor1d на IIзыке С#


using System;
public class МуАрр
(
static void Main ()
(
СОПSОlе.WritеLiпе("Привет из С#");

, 8е110 wor1d на .зыке vв .NET


Imports System
Public Module МуАрр
Sub Main ()
Сопsоlе.WritеLiпе("Привет из VB .NET")
End Sub
End Module
11 8е110
wor1d на языке Мanaqed Extensions for С++
#include "stdafx.h"
using namespace System;
int main(array<System: :String ~> л аrgs )
(
Сопsоlе::WritеLiпе("Привет из managed С++");
return О;
r
Глав:а 1. фИЛQООфl'lЯ . NET 69
3аме'):'ИМ, что 1Щесъ 11 любом из язьщоц используетсJ:l класс Console. (щреде,лен­
ный'впространетве имен S~уstеП\. Если отб]юситъ неаначител:ьныесинт<шсичеСlЩе
вариации,то ЭIJ'И три приложепия ВЪU1IЯЩIТ очень похонщми, :как по форме. TaIt и:
по'лorике.

Очевидно. вашей главной цеJIЬЮ. Н,ах разработчика .NEТ. нвлнетс.FI получеJ-ше


'Исчерпы.вaIOщеЙ m:rфорМЗЦJЩ обо вСеМ разнообразии типов, onpеделеFЩЫX в рам­
ках (мнorочислениых,) пространс:гв 1Щен .NEТ. IЛавным из пространств имен. о ~p­
торых следует знать, является S'ys't:em. Это ДР0СТра:нство имен предлarае-т базовы:й
набор ТИПОВ', :которые ВЫ, 'RaН ра.зрабо'ГЧ:ЦЕ .NEТ. будете испощ;эовать снова и сно­
ва. Фащuчес:ки !3ы не СМQЖете ПЩ:ТРQИТЪ ни одного реа.лцно работающего С#-цри­
.llPженин., не СОСJ:raвщисъ. кaR~. 113 пространство Щ\II'ен System. В табл. ).4
преД1larаютс.в кратк;ие одис.amзл: неноторых [НО, КОНeчJ:lО Же. не все..х:) пространств
.и:мен J\lEТ,

т.Cinица 1.4.. Пространства имеlit .NET


ПростраНGТВЭ иМен .NEТ ОnИС8tt и е

sуst.ещ в рамках System ВЫ найдете множество полезных 1111П05,


связа~IНЫХ с ВНУТРенними даtlНЫМИ" ма:reмаП1'lескими ВI:!IЧИС.
ле'НI.fRМИ, перемеЖ-IЫМИ ОКРУЖения, генеРl.1рааанием Сllучай­
Ных Ч1llсеl1 и сбаром мусора, а таlCЖе с 06раlDаткой ТИПИЧНЫХ
ИОlU1ючитem.Ных си1'jflЦИЙ и атрибуroв
System,Collec~ions Э'(\IIпростра:~стsa имен опред.еляют р;щ IШнтейнерных абъек­
Sys,tem.Gollecti0115,Gene:rio тав (ArrayList. 'Ql.leue и т,д,) , '3 также базовых ТИПОВ и
интерфейсон" которые ПОЗВРЛЯlOт t;ТpОИТII полйзавателЬСlC:ие
КQJ1J1екции. В .NET2.Q П1ПЫ коллеlЩИЙ обладают даполнитель­
ными QЩИМl-1 вдэможностями

Sysbem.Data Эти npaCTpa~ICTBa име~ ИСПРЛЬЗУЮТGiI ДЛЯ взэ.ИIv!QдеIi!СТВИI1 G


Systern .Data . Odb t: Вазами A<lHllbl)( на основе ADO,NET
8yst!3m. Data .. ОrасlеСliепt
sУstеm.D~tа.ОlеDЮ
&ys'tem. Оа1:а. 5qlClie:nt
s
Ву Ьет" Di ачпс) 5 t 1сs, 'ЗДесь вы Н2Йдщте М~lOже(lтватиno'В, lI:0'fQpble могут ИСПОЛЬЭQ­
El.a~ ДI1M npаграммной, отладки и трQc;cJ.tровки ИСХОl\н.оro кода

Зуs'Ьеrn .Drawirrg 3:цесь вы flаидете МНlJжествот~пав для работы с графt.t4ески,


~уstеm.Drаwing.Ьr,аw.iпg2D мй лримитиl3aМИ, таl<liми кш растровые изображения, шриф­
System.Drawipg.printing ты и пикroгрclММЫ, а т8.юке ДЛЯ ВЫIВOДa >la пе'lаТh

System.IO ЭТи прастранства имен ВКЛЮLIJ'lЮТ cpeДl::твa фаЙJ10ВОГО ввода­


вУsctе.\1\.Щ.СощрrеSS!Оr! аывода, буфер"ЗSЦИИ \JI т.д. В .NEТ 2.0 npoc;rpaнcтвa имен !с
&ystem,IO.Parts предпзгают ПОМеРЖЧ ЩЮ'ИА' и работы j) портами

SуstеЩ,Nеt Это проотранVТВQ имен (как и дрvгие pOACiГВeHtllbIe npостщrн­


ства имен) сод&ржит 'j'ИПЫ,овя3at-lные с сетевым программи­
РOlJанием (запросы/отвеТЬ!, OOKвIbl, ItOHe"IHbIe 1'О"lIЩ ОО~<дИне­
ний и т.)1, ..)
SУБт,ет .1!.efl.e cti оп эти ПРОфJранства I4MeH определяют типЫ, 1iJвязаflf.jЬ/е с I)ООа'
SysteI!1.Ref1er;ti'on.Emit ружением типов в среде ВЬlполнеНИR И' динамичеСkИМ' созда­
ниемТИПQВ
70 Часть 1, Общие сведения о языке С# и платформе .NET

Окончанне табл. 1.4


Пространства имен .НЕТ Описание

System.Runtime. Это пространство имен обеспечивает средства взаимодей­


InteropServices СТвия типов .NEТ с ~неуправляемым программным кодом"
(это, например, DLL на базе С и СОМ-серверы)

System.Runtime.Remoting Это пространство имен (среди прочих) определяет типы, ис­


пользуемые для построения решений на основе возможно­
стей СЛОя удаленного доступа .NET
System.Security Безопасность - зто неотъемлемый аспект платформы .NП
В пространствах имен, объединенных идеей безопасности, вы
найдете множество типов, связанных с разрешением ДОС1УПа,
криптографической защитой и т.д.

System.Threading Это пространство имен определяет типы, используемые при


построении многопоточных приложений

System.Web Ряд пространств I/IMeH, специально предназначенных для раз­


работки Web-приложений .NEТ, включая Web-сервисы ASP.NEТ
и XML
Sуstеm.Wiпdоws.Fоrщs Это пространство имен содержит типы, которые упрощают
процесс соэдания традиционных GUI-приложений (приложе­
ний с графическим интерфейсом) для настольных систем

System.Xml Связанные с XML пространства имен, содержащие множество


типов, используемых для взаимодействия с ХМL-данными

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


Не помешает повторить снова, что пространство имен является ничем иным,
как подходяIЦИМ для человека способом логически понять и организовать свn­
занные типы. Снова рассмотрим пространство имен System. Можно считать, что
System.Console представляет класс, названный Console и содержащийся в про­
странстве имен System. Но для среды выполнения .NEТ это не так. Механизм сре­
ды выполнения видит только отдельную единицу, названную System.Console.
В С# ключевое слово using упрощает ссылки на типы, определеШIые в данном
пространстве имен. Вот как оно используется. Допустим, вы строите традицион­
ное приложение для настольной системы. В главном окне должна отображаться
некоторая диаграмма. основанная на информации, полученной от внутреI:шей
базы данных. и логотип компании. Конечно. ДIIЯ изучения типов в пространствах
имен требуется время. но вот несколько очевидных ~кандидатовМ, подходящих для
ссылок в описанной выше программе.

// пространства киев, нвобхоДИll»В ,цnJl данного DpЮJо.еНИIII.


using System; // Общие ТИПЫ базовых классов,
using System.Drawing; 11 визуализация графики,
using System.Windows.Forms; 1/ GUI-элементы,
using System.Data; 11 общий доступ к данным,
using System.Data.SqlClient; 11 ДО СТУП к данньш MS SQL Server.
[лава 1. Ф~ЛОСОфI1Я .NEi71

Выбрав Hel~oтopoe число цространств l>IМeн (я уназав CCдI.JntI4 на .компоновочные


БЛОiШ,1tоторые их опреде..ляют).. БЫ получаете В03МОЖlIQСТЬ создаватъ эRЗеl\(IIJIЯ­
ры соответствующих типов. Например. если вы хотите соэдаlJ"Ь э}(3емrшлp класса
Bitrnap (И3 ЦPOCTpaнcTBt1 имен 5ystero.Drawing), ВЫ можете }ICnOJIЬЗовать следую­
щий npогрaммUblЙ код.

1/ ~ список пpDС:Щ'РiUlС!rS ИКQ, ~caom..sY4DlJDt. ~о.. ф&ii:n••


'usingSуstеш;
u"ing Systern .. Drawing;
class МуАрр
{
plJblic "Qid DisplayJ;.ogQ ()
{
11 СоSJtа.ии. иао(SpucевИll:20Х20'.
Bi tlnap ефmрапУLоgL> =- new Bitmap (2,О, 2 ()) ;

ПQСКQJIbКy ва:ше прилож~е ссыдается на $ystern. Drawi.ng, кmиmля.ТОР смо­


жет ВЫЯCНflТЪ. что :клаОС Bi tmap явзщется членQМ j'Щi~анного проотрщrства имен.
Если бы 'вы не}'lШЗали здесь пространство имен Sys'tem.Drawinq. то получили бы
ошибку RО'МIIИJIЯЦИИ. НО ДJПi оnpеде.левв'Н переменны:х можно также ИlЛI0ЛЪ30ватъ
rw.iZн:oCmt:aO D~деJJeюфе, или йikoлюmнпe wи.я..

/J Здесь Systetil. Drawinq ив }'1t~ae'1'QJI~


\181П9 Sys temj

clas-s МуАрр

f
ри:ЬН с v.oid Displ ayLogo О
(
11 Иcnom.ЗО_aJWе а.БС0lIJD'L'801'О ии. . .
Sy.stero. пrаwiug. Вi:tmap r:;ompa,nyLogo =
new Syst.em.Drawing.Bitmap('20, 20);

йспоЛЬЗование абсолютliЫX именДJIJI определeнuятипа, :КОrreЧЕО~ упрощаетпо~


нимание npограммното кода. 'НОЯ ..цумаю. И вы не стайете .возражать. что кпючевое

c.1l0BO С# '.lSing yМeHыnaeт объем необк.оди:моro ввоДа. В aтoMТce8Cre мы будем ИЭ~


беrаТЬИСП0ЛЪ30вайИЯ абсолютных имен (за ИCКlIЮченвемтех алучаев, Kor,цa из'-за
~TOГO возникает явная неОДfIозвачность)', о'Гдавая Dpедпочте1tИе использованию
RJiЮчевого СЛова l1'si пч,
При сЭтом: следует понимат.Ь. что Использование us:tng явnя.стcs.c JIИUIЬ aлI:n'~риа­
ТИВОЙ ИСПDЛЬзовани" абсолютных имен. nосколысу в ПРОrpaмм1ЮМ к-()де CIL Boerцa
ИСIIOЛbЗyIOТся абсолютные имена. ~ ~Т() оба yRaЗэ:IOlЫX подхода Дa:JIOТ с.овершеН1W
rЮU1ia1Фвые реэу..!Ilй'аты в CIL 11 с l'оЧRt1X зрения nPOИЗВО,mneдыюcnt, и С ТОЧЮI эре­
дИЯ ~aMepa кOl\ЩОnOВОЧН:ОГО о.."1Ока.
72 Часть 1. Общие сведения о язЫке С# и платформе .NEТ

Ссылки на внешние компоновочные блоки


Вдобавок к указанию пространства имен с помощью ключевого слова С#
using, необходимо указать компилятору С# имя компоновочного блока, содержа­
щего реальное СIL-определение соответствующего типа . Выше уже упоминалось.
что многие базовые пространства имен .NEТ содержатся в mscorlib.dll. Однако
тип System.Drawing.Bitmap содержится в другом компоновочном блоке с именем
System.Drawing.dll. Большинство компоновочных блоков .NEТ Framework разме­
щается в специальном каталоге. называемом GAC (Globa1 Assembly СасЬе - rло­
бальный кэш компоновочных блоков). На машинах Windows это может быть ката­
лог %windir%\Assembly. как показано на рис. 1.5.

dl!Sys!мI.lXedDrv$erv ... 2.0.0.0 ьозf5f7f1!dSOaЗе мsn.


CSy.Iem.lXedDrySeni... <.0,0 ,0 ЬDЗf5f7flldSOaз..
IIIJS\l$Iem.Dr"wi1!I LO.5000.D bDJf5f7fl!d5DllЗе
,. '4;;; 2.0,0,0 ЬDЗf5f7flldso..з. МSIL ..,
.Sysll!m.Dr"W1ПQ,Oesi!jr1 1.0.5000.0 Ьо3fSf7fl1d508з..
::tфsys_ .Dr..\W1II. ~ 2.0.0.0 bDЗfSf7f11d5Dllз.. МSJl. .~
;tj!~iУJйtf1rJt~~:5J:;:,<_;;л~i!;jjЛ~{:i:&:i~I;Дz:{'iJi/Git1j;~1;irffЖ}<й..fl{ff!);~ffi1:.~~ffJi!JfiA7/ifIf!i!f!fJ~1 :II"J
Рис. 1.5. Библиотеки базовы)( l<Лассов в GдC

В зависимости от используемого инструмента разраБOТIШ приложений .NEТ мо­


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

Использование ildasm.exe
ЕсJШ вас цугает перспектива освоения всех пространств имен платформы .NEТ,
вспомните о том, что уникадьность любого пространства имен заключается в ТОМ.
что оно содержит типы. некоторым образом семантически связанные между со­
бой . Поэтому. например. если вам не нужен интерфейс пользователя для простого
консольного приложения. то смело можете забыть (среди прочих) о пространствах
имен Sуstещ. Windows. Forms и System. Web. Если вы строите приложение для рабо­
ты с изображениями, то вам вряд ли понадобятся пространства имен для работы
с базами данных. К тому же. как в случае любой новой бибJШотеки готового про­
граммного кода. вы можете учиться по ходу дела.

Утилита i ldasm. ехе (Intermediate Language Disassembler utillty - утилита ди­


зассемблера промежуточнorо языка) позволяет загрузить любой компоновочный
блок .NEТ и исследовать его содержимое. включая соответствующий манифест.
программный код CIL и метаданные типов.
По умолчанию файл ildasm.exe должен быть установлен в папку C:\Program
Files\Microsoft Visual Studio 8\SDK\v2.0\Bin (если вы не можете найти
r
rfliBa 1. Философия .NEТ 73
i1dаэm.ехе в указанном месте. npoCТi) выполните поиск файлало юпочу Wi1dasm.exe"
на своей маШине).
Обнаружив и ~апустnв Э'I'()l' файл> з ОТRpывшемся: окне выберите КQмзиру
Мt!'ню Fileq OP~'h и перейдите R коt.шонов()чному блоку . :который вы хотите »с­
следовать. С целью иллюстрации здесь (рис. 1.6)показм вJомxrоновочiiый бло:к
C5harpCalc1Jlatar.exe. о "оторомуже шлз речь выше. Утилита ildаэm.еке npед­
C'taвляет c:rpyнтypy RОМПОНОВО'LШОГО блона, исnoльзуя: всем 3НaRОМЫЙ формат .де­
рева nPОСМотра.

~ МА rJ.1 r-'es т
f' • Сill~"Iato!Ex/IП'fP1e
" • Qlw&!II'Ex".CI:Ik:
~ ,d_.~bk ЬШо n'be(oteFleldrtJit
• ,dDrJ~~()
дdd , IrtЗZ(IntЗ2,J1'1tЗ2)

g.~8mpl&.~
.. ,CJМS pojttc ",,10 «.1>1 befщl'i8ldln~
• .МI'ЮIdI)
а Maln':~

Рис. 1.6. ваш НQВЫЙ лучший друг i ldasm.€'xe

Просмотр СIL-кода
в ДоПOJntение.к тому. "11'0 ВЫ можете видеть прострадетfЩ имен. ТДПЫ и Щ
члены в Щ)мпоновочном блоке. ild<lsrt1.exe позполя:ет также прос'Мотр~ СIL-иц­
струкции Л1Обого '<Ше:на. Напр1-IМеРJ есл8. выбраТ:Q' ДВОЙlD>Щ Щ6JIЧШ):М МС1'ОД Мдin ( j
масса Са1.сАрр.'!'О noлвцтс.я: отдельное 01ЩО, в :котором будет QТображаТЬCSj: соот­
.g'еТствующиЙ CIL-ICОд. (рис. 1.1).

• ntlt<YPllint
11 J:Od!! $12'"
.lIГoIхst;щlC S
.1DUl!i tnit ([11] t:l~s Calctйilto"E)(~lJ!.Cal.c с.
11] tnt32 ilnS)
n... ll!lJlj
ll_ •••• : inst.anc... void Cil1C1J1atnl'ExaJIIII}~.Calc::,.ctorO
JL_"I5~ rtlDf:.1
1L "16~ ld]:nc.1
ICall1: ldc-.1!I& •.5 l'
1L-•• I9= ldf;.tJI.s .~
lL:"Ib~ culvil't inst_ancl.' 1nt32 &illculatorEllaI'lPJ ... ,.Cillc::Add{ .... L~~~

P...~ 1.7. Г1росмотр OIL-КQд<!


74 Часть 1. Общие сведения о языке С# и платформе .NET

Просмотр метаданных типов


Если вы захотите просмотреть метаданные типов для эarpуженного в настоя­
щий момент компоновочного блока, просто нажмите <Ctrl+M>. На рис . 1.8 ПОRaза­
ны метаданные для метода Calc.Add ().

IIrthodКil .. : Add (1611.113)


fligs : [Publ1c] [Hide.ySig] [ReuS.Slot} ( .......6)
RUR : "".12'"
l.,lFligs : [IL] [Кilniged] ( •••••••• )
Cil1Cnuntn: [DEfAULT)
h.sThis
ReturnTJP.: 1'' -
2 Argu. .nts
Argu..nt 11: 1.-
Argu. .nt 12: J.-
2 P.r.... t.rs
(1) P.. r ...Taken : ( ......11) Н.... : х flags: [попе] ( •••••••• )
(2) Para.Token : ( ......12) На.е : у fl .. gs: [попе] ("'.'.II)

Рис. 1.8. Просмотр метаданных типов с помощью ildаэm.ехе

Просмотр метаданных компоновочных блоков


Наконец. если вы захотите просмотреть содержимое манифеста компоновочного
блока. то вам нужно двойным щелчком открыть пиктограмму MANIFEST (рис. 1.9).

Рис. 1.9. Двойной щелчок на этой строке покажет


манИфест компоновочного блока

Не сомневайтесь в том, что ildasm.exe имеет не только те опции. о которых


говорилось BЫ1lIe . Дополнительные возможности этого инструмента будут обсуж­
даться и дальше. По мере чтения материала книги я рекомендую вам просматри­
вать ваши компоновочные блоки с помощью ildasm.exe, чтобы вы видели. как
ваш программный код С# транслируется в неэависимый от платформы програм-
f

МНЬ1Й :код Сп,. :Конечно, "JТOбьr быть сyne,рзвездой С#,. сов(':ем не о(5язатe.юmo быть
ЭR€пертом по проrраммному K€lд.Y CIL, но ПОНИМЩие е~тахсИCCl CIL 'TWXЫto укре­
r:;r:ит'ВЩШJ "мyc1WJIЫ лрогра:мм:ировaшut~,

Инсталляция ер,еды выполнения . NET


ДmI B~e не ДОЛЖНО быть сюрпризом то, что компоновочные блЬки .NEТ MO:ryт
ВЪ1Полн.ятьсл TOJIЪ1W на машине, на 'Коroрой УС1Га:новден :каркас .NEТ FrameW'ork.
Для вас, как ДЛЯ раэрafimчm:кa .NET-прил:ожеНИЙ. это не дрлжно быть npоблемой,
пOCШШЫty :ваша мащина буд~т долЖным образам СI~ОВфиrypиpoвана уЖе в процес­
се у:станоШtИ свободно Aoc-rynнoro па:кета .NEТ FrameWork2.o ЭDК (или любой ном­
мерчеСRОИ среды разработки .NEТ-цpmюжений, например V:isual Stud10 20(5).
Одна:ко, есJ!Й вы развернете КDМПОНОВОЧНblЙБЛОR I"Ia, номпъютере. Который не
имеет установленной системы .NE:I', этот в:омпоновочныИ блок выполняться не
СМожe'J:. По Этой причине Мicrosoft npеДJIагае"1 УстановоЧEblЙ Ilf:illeTdotnetfx.exe.
который .может быть бe€ПJlaТНО .Il0ЛУЧен и установлен ВМесте с вашйм npотрамм­
:н:ым обеcnечением.. Эта. уставовочнанпрщ-рамма ВЮIIOЧeна в .NE1' FrclIDewod 2.0
SDКo а также дacтyrma для беcnлaтнайз~рyзIOi с }'3.!"Ia Мicrosoft.
Поме установки dotnetfx. <.;Ха ваша мапrииа будет еодержать БИБлиотеки базо­
вых 1tлaссов .'NEт, фaйJIы. среды въщоmшшш ,NEТ (:rrusi.:::oree.dll) и доttOЛНИ'I'e.nblt11J
инфраструктуру.NEТ (например, GAC).

ЗаМечание~ Пр~ поСтроении WеЬ"'приложеf<JИЙ .NEТ не предпрпаГается, 'П"о на маШИНе коне,ЧliОО"О


nольэователя б)/дет устаНовлен каркас .NET Framework, n.О!ЖО!l1Ь~ .браузер KOl-lеQtlого nОJlЬЗОВQ­
.еля лpDCТО Т1GJIIучает общий HTML'K{)~ и. ВОЗМDЖНО, Jаva6сгip\·код ЮJИента.

Платформенная независимость .NEТ


в зав~ршеFЦfе этой ГJrавы позвольте мне сказать неаКОлРRО слов ПО поводу не­
З~И(JИМt~сти ШIатфорМ1:!I ,NEт. Неожиданноотью дml многщ раарабоТ'ШКов ЯВJ1Н­
f;ТШi ТО, 'Что RшщtQНОВОЧJfbl6 блоки .NET MOryт ра;.зрабатьmaться и выполняться в
операциоНl:lhl4 С'J!СТе:мщ, Отmrчн:ыx оТ олсрациоиных систем Мic:rosoft (~C 05 Х.
'МНОГQЧЩ:JJeщiЫе ва,РJJ;адии Liщщ, в частцост,и Веов и FreeBSD и: др.). ЧТQбы по­
НЯТЬ. lJQчему ЭТQ возмоцщо., мы С вам,а доllЖЩ>f paCCMOТP~TЬ еще- одну аббревlIЩ-
1УРу, используемую во "вселеаноЙ· ,NET: это аббрев~атура си (CommonLa.nguцge
Infrastrцcture - общеязщкова.а илфраС"'.rpywгypа}.
Доуда Мicr()soft в:ы:пустила ЩlЫК ЛРОГРa1l,2МИрования С# и р:ла1'форму ,NE'f, она
выпус.тила ТЩOJtе МНЩRес~во Ф9рl\taJIЬ:щ,IК AOНYМewroJ3 .• поторы~ описamr сшr;raxt::.ис
n .ССМЩIтику языков G# и CIL. фор~~Т .('!.ОМЦОНО;ВОЧlj0j'О t!дOK3 .N$Т. б~()ВI:Щ! про­
CTp~'I;вa ИМен: l>i papory ТИDОте~~roI'{) МeJЩ.FЩЗAoIа среды ~ЫПDДН~ .NEТ (.JJз­
.весТНQГОТаюке пет наэвани~м VШ:;, иди VirtLЩ.1 E;reС1ЩЩl Sуstf!Ш - :виртуальн;э.я:
система ВЪ1noлненщJ,). Еще лучше ТО. что все эти докуменТЕ предеТaщtещ.r в орга­
низацию Еста lntеП1аtiе:iш1 (ht tp ;! / W'WW , еста- interna ti 01"1&1 • org) ;D,II.П ~е]ЦЩе­
ния их в качестве официальных междунцроДfIЫX СТЩIдарl'QВ. Иитереq10ЩЦМИ н.ц.с
GПе:цификaцИ.FIМИ .яв.лmoтс.я:
76 Часть 1. Общие сведения о языке С# и платформе . NEТ

• ЕСМА-334: спецификации языка С#;

• ЕСМА-335: общеязыковая инфраСТРУК1ура (CLI).


Важность этих документов проясняется, если эаметить, что они предоставляют
третьим сторонам возможность строить дистрибутивы платформы . NEТ для лю­
бого числа операционных систем и/или процессоров . Спецификации ЕСМА-335,
наверное, более "содержательны", поэтому они разбиты на пять разделов, I<aк по­
казано в табл . 1.5.

Таблица 1.5, Разделы CU

Разделы ЕСМА·335 Описание

Раздел 1. Архитектура Описывает общую архитектуру CLI, включая правила CTS и CLS,
а также работу механизма среды выполнения .NEТ

Раздел 11. Метаданные Описывает структуру метаданных . NEТ

Раздел 111. CIL Описывает синтаксис и семантику CIL-коАа

Раздел I~ Библиотеки Дает аысокоуровневый обзор минимальных и полных библиотек


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

Раздел V, Дополнения Коллекция · вспомогательных" элементов, таких как рекомендации


по проектированию библиотек классов и подробности реализации
компилятора CIL

Заметим. что в разделе IV (Библиотеки) определяется минимальное множество


пространств имен, которые представляют только базовые сервисы, ожидаемые от
СLI-дистрибутива (коллекции, консольный ввод-вывод, файловый ввод-вывод. по­
точная обработка. отображение, сетевой досryn, базовые средства эащиты. XМL-Ma­
ниnyляции ит.д.) . Такой СLJ-дистрибутив не определяет пространства имен. упро­
щающих разработку Web-приложений (ASP.NEТ). досryn к базам данных (ЛDО .NEТ)
или построение графического интерфейса пользователя (WIndows Fbrms).
Благоприятным. однако, является то. что главные дистрибутивы .NET рас­
пространяют библиотеки CLI с зквивалентами Мicrosoft дЛЯ ASP.NET. ADO.NEТ
и Windows Forms. чтобы обеспечить полноценные платформы разработки про­
изводственного уровня . На сегодняшний день есть две главные реализации CLI
(кроме предложений Microsoft, предназначенных только для Windows). Хотя в
зтой книге рассматривается создание .NET-приложениЙ с помощью . NЕТ-дистри­
бутива Мicrosoft. в табл. 1.6 представлена ТaI<Же информация о проектах Мопо и
РоГШЫе.NEТ.
как Мопо. так и Portable.NEТ обеспечивают ЕСМА-совместимость компилятора
С# и механизма вьmолнения .NEТ. примеры проrpаммного кода, документацию, а
также многочисленные инструменты разработки приложеНИЙ. которые. по функци­
ональности ЭI<вивалентны инструментам, входящим в состав . NEТ Framework 2.0
SDK от Мiсrоsоft . К тому же Мопо и PortabIe.NEТ поставляются с компиляторами
vв .NEТ, Java и С.

Замечание. Если вы хотите узнать больше о Мопо или PortabIe.NEТ, прочитайте книгу М . J. Еаstол
и Jason King, Cгoss-P/atfoгm . NEТ Deve/opment: Us/ng Мопо, PortabIe. NEТ, and Micгosoft. NEТ
(Apress, 2004).
r Глава 1. ФИЛ'ОС{)фИЯ .NEТ

Табnица 1. 6 •. NЕТ~дистри6утивы с ОТХРЫТЫМ ИСХОДНЫМ KQдOM

.h .ttp;./ /w,wW.mОГiO-рl:оjес"t:.соm Проект Мапо является дистрибутивом Cll с 01ХрЫТЫМ ис­


ХО.QЮ>lм КОДОМ, предliазkаченl1ЫМ ДЛЯ раЭnИ"tныхвариаfiТQВ
.unux (Н2IТ1РИМflр, SuSE, Fеdоra:и т.д.), а твкже Дl'IЯ WiпЗ2 и
МQcOSX
ht tp; l/wWw. dоt.gШ:J. org Portable.NEТ ~ ЭТО другой дистриб~в CLI С urnpытЫМ ис­
ХОДНЫМ KQДOM, преднаэftа"!е~ныlll ДJlЯ множест~а операци­
ОНfiыхсистем. PortabI~.NEТ ",аЦе-лен на ТР, ' чтобbj обсЛyJКl1-
8Зп. как можно БQлЬше операЦИQftНIiIХ систем' (Wln32, AIX.
BeOS, Мае os К, Solar/'s, вое maвHыe варианты UnlJ)( и 'r.l(.) .

Р· езюме
Целью ЭIТОЙ ТJЩВЫ бl1LЛО оn:исamю базОВЫХ :концепций. :неоБхQдимых дшя освое­
щщ QCTW~OrO 1I:iаJ'ериала этон:книги, Сначала БЫЭIЙ рассмотрены ограничения и
сложн;щ:'n1 технwюпЩ, поSmИВТrrиxся Ao..NE'Y,· а змем БЬUI предложен обаор того.
1mE' J'tlEТ и С# цытаютс'я: УПРОС'FИТЬ существующее IЮложение вещей.
В СУЩНостИ •. NEТмОЖНО свёсти К механи3Мусредъгвыnoлнения (mscaree. dll) и
БЩinиoтe]:щБаэовых классов (msc"rlib.dll и сonyтcтвyюП:J;Иe файлы). ООщеязhtКOвая'
среда ВJaПlо.tIНении (GLR) способна Р:РИШl.'IЪ любой БШiaрlЦ.IЙ .NE'f-06ъеRТ (назьtвае­
мый RОМп~нов!JЧНblМ блnиОМ), е.слиТОЛЫ{О этот бинарнЫй объект ПОДЧИRЯe'I'CЯ I1pa-
вшщм. упр<шл.вемoro пporpaммRorо кода. как вы убеДИлись. коМПоновочные блоки
сод€ржат СlIгинструкции (в дапо.11lieiIИe х метаданным ТИПОВ и манифес-l)' компо­
новочного БЛQБа). ItOTOpble С 'IШмOЩьюJ1Т-КОМПИЛЯТо'ра КОМnИЛИPYЮТСЯ: 11 спеЦlХ­
фИ"'reс.mе ИНстр}'1ЩИИ плаТфQрМы. Кроме 'I'Oro. была выяснена роль общеs3blКОВых.
спецификаций (CLS) и общей сис)'емы тИПОВ (CТS),
3&тем БЪL"Jа рассмотрена утилита i 1 dasm" ~Xe .. а также то, ltaк с помощью
dotnetfx .ex€ наетроить мз т ттину Д2Ш исполЬзования .NET-пр.иложенйЙ. Б закmoче­
вне было с:каз.ано несколъко слова незавпсимоп от платформ природе С# и .NEr.
r,

ГЛАВА '2
Технология соз,дания
u
приложении

ная3ыIеe С#

К ах разработчик проrрам.м на sыьще С#. вы имеете возможность выбрать


JiЮбой из .множества дocтynныx: инстрУ14"eFIТОВ разработgи .NET-приложС}­
НИ'Й. Цt'J1ЪЮ э'tOЙ rnааы ЯSляетс.IJ обзор C~ J;'азных инструментов разработки
.NEr. в:кmoчая. КОRe'ШО же. Vlsua1 Stud10 20(J5. Однако :начнется глава с расс:мо­
:rрения Rомm:lлятора Щ)мандНОЙ СТрОIЩ С#. с.:,; с . ехе. для- раБОТht с которым буд~т
достаточно самого IrpостщотекСТQlJОro редантора. налример проrpaммы Бдокнот
tnotep.ad.€xe). :Кроме того. МЫ с ВaМIJ ВЫЯСН:IW. КЗR 1IЫп0ЛНiП'ь отладку КОМПОНО­
вочнЬrx блоков .NEТ (' командной СТРQJШ С IIОМОЩ:ЫО Cordb.g. ехе.. Освоив компи­
ляцию и O'l"Лад'КУ К0МЦОНОВОЧНЫХ блоков бе;з графичеCIЮГО mrгeрфеЙса. мы затем
выясним. :как моЖJ-IО редаJCТироватъ JiJ J{IiJМПилИровзть ФаЙЛЫ исходного 1tода С# с
помощью при.лОНСе1ПfЯ Th:XtFad. .
Конечно. с тeltcToM этой :IOIДг.и можно раБОТагп.. ИСIiОЛЬЗУЯ ТОЛЬко csc .e~e и
Б:!rоюют /ThxtPad. но я ~. вы 3aИFГгересованы: в освоении б'О. . Iее широ:ких В0'3-
можвосте'Й. предлarае:мъrx в рамках: со.временных IDE {Ihtegrated Development
Envl.ronment- интетрировщma:Rсреда рцэрабоТRИ], Поэтому:мы рассмотрим тая­
же SharpDevelop _. интеГРИРОВa:нFIj711i1 среду разработки с oткpьrrым h'схоД'6ЫМ тек­
СТОМ. По ф)'1Ul:IUiоналЬНQСТИ она шщкурирует со многими коммерч-ескими сред­
ствами разработки ,NE'f, обладая тем дщюл:ните1Ibl:Iым преимуществом. что она
бесплli'n.Iа. А nQC1Le краткого oocymдel;IтJ воsмoжностd! VIsua1 С# 2005 E~ress· мы
npис'I}'IIйМ к рассмотрению Visua1 stщ;liо 2005. ЗакоНчится глава небоm.щим об­
зором це.iIQrо ряда ДОПU.lllЩ';Гe.llpНЫ инструментрв разраБОТ!GI .NEТ [многие JIЗ, хо­
i"OрыХимеют откры1ый и~одиый щщ1 и реКОМe.JЩaЦИЯМИ по ПОВОЩ" того. ШlК эти
инструменты получить.

Устан0вка .NET Framework 2.. 0 SDK


Пр!':щде чем Ш1ча'l'.Ь строить .NEТ~ПРИJIОЖения • .исnолъзуя язык про;грам:миро­
В$И;R С# И к.1.p~e разработки прmlOжeRИЙ .NEГ Ftamework, СНаЧала li;Y'ЖНЬ уста­
ПОВИТЬ своБQдщJ д9Сryпны:й шшет .NEт Framework 2.0 SD}{ {Software Devt:lopment
IШ - КОМПЭ'ЩК'1' средСТв р~раБЬткI-I прогрaммttогообеспечеция}. Gдед,ует 3ВаТЬ о
80 Часть 1. Общие сведения о языке С# и платформе .NET

том, что .NEТ Framework 2.0 SDK автоматически устанавливается при установке
VisuaI Studlo 2005 или Visual С# 2005 Ехргевв. поэтому если вы rшанируете уста­
новить одну из указанных систем, то загружать и отдельно устанавливать пакет

программ . NEТ Fгamework 2.0 SDK нет необходимости.


Если у вас нет Visual Studio 2005 или VisuaI С# 2005 Express. то откройте стра­
ницу http; //msdn. microsoft. com/net framework и выполните поиск по клю­
чу ~.NEТ Framework 2. О SDK". Перейдя на соответствующую страницу, загрузите
setup.exe и сохраните этот файл в подходящей папке на своем жестком диске.
Затем двойным щелчком запустите этот выполняемый файл, чтобы установить
соответствующее программное обеспечение.
После завершения установки на вашей машине появится не только необходи­
мая инфраструктура .NEТ, но и множество инструментов разработки с очень хо­
рошей справочной системой. примерами программного кода и обучающими про­
граммами. а также различные официальные документы с описанием системы.
По умолчанию пакет .NET Framework 2.0 SDK устанавливается в каталог
С: \Program Files \Microsoft Visual Studio 8\SDK\ v2. О. Там вы найдете файл
StartHere.htrn . .который (в полном соответствии с его названием) может служить в
качестве отправной точки для доступа ко всем разделам документации. В табл. 2.1
предлагаются описания некоторых подкаталогов из корневого каталога инсталля­

ЦИИ.

Таблица 2.1. Подкаталоги корневого каталога установки .NET Framework 2.0 SDK
Подкатаnог Описание

\Bin Содержит большинство инструментов разработки .NET-приложениЙ.


В файле StartTools.htm предлагаются описания всех утилит

\Bootstrapper Почти все содержимое этого каталога можно игнорировать, но следует


знать, что именно здесь, в подкаталоге \Paekages\DotNetFx, на­
ходится dotnetfx.exe (см. главу 1)
\CompactFramework Содержит программу устаноаки ,NEТ Compact Framework 2.0
\ Samples Содержит программу установки набора примеров .NEГ Framework 2.0
SDK О том, как установить примеры, говорится в StartSamples .htm

в дополнение к файлам. установленным в каталог С :\ Рr оg r а m Fi 1е s \


Мiсrоsоft Visual Studio 8\SDK\v2.0, программа установки создает подкаталог
Microsoft . NET \ Framework в каталоге Windows. Там вы обнаружите отдельные под­
каталоги для каждой версии .NEТ Framework, установленной на вашей машине.
Внутри подкаталога, соответствующеrо конкретной версии. содержатся компиля­
торы командной строки для каждото языка, предлагаемого в рамках Мiсrosоft .NEТ
Framework (зто CIL. С#. Visual Basic .NEт. J# и JScrtpt .NEТ), а также дополнитель­
ные утилиты командной строки и различные компоновочные блоки .NEТ.

Компилятор командной строки ДЛЯ С# (csc.exe)


Для компиляции исходного кода С# есть целый ряд возможностей. Не касаясь
VisuaI Studlo 2005 (и различных ЮЕ сторонних производителей) , здесь можно от­
метить компилятор командной строки для С#. csc.exe (где еэс означает аббревиа-
t

Глава 2, iехнолorИR СОЭ~НИЯ ПРИЛOJ:еIotИЙ на языке С# 81


туру для с-Эhшp Cornpi1:er- RОЫl1ИЛJl'ТОР С#), 1; ПОМОЩЬ1f.l Koтoporo МОЖНО создавать
RОМ:nОНОВОЧНЬ1е блоки .NEт. Указанный файл В,Х;ОДИ'I' в КОЮIJlект поставки .NEТ
Framewnrk 2.0 ЭОК. Вы. хонеЧН9 Ж~ не захотите создавать большие npиложеНiUI с
помощью' компилятора ХО~ОЙ строки, НО :umТb, кан itомпиЛJфОвать '*. св-фай·
.ttы ВРУЧНУЮ. все , же важно . Можно yпaзa:r:ь несю:шь:ко 'причин. ПО ,ROТOpыы : вы ДО1IЖ­
RЫ иметь представление 1) соотвеТС'l'вyIOщем процес~.

'.' самыы очевИДf'IЫМ ЯIiJlЯетспто, что ~Ы можете цросто не :иметь Vlsual Sttidlo
2005~

• в IЩШИК nлaнax :Может быть ИСПОЛЬЗ0ва.ние а~томаТИЗtfрованных средств


разработки, ' таких кal( MSBuJld ЮIИ NAnt.
• Вы можете отремИТI>СЯ к расширению своего ЛОНИl\olЩlИЯ си. При щполъзо­
IЩ,НИИ графичecJ:ШX средств раэраБОтни прююжеюIЙ вы все рацио mt-eтe ~­
cтpyrщии csc.exe о том • .кан: о.брабаn.rвать ИСXQДНые фaйлъJ С,. С атой TO'ЦGI
~peIn'J1 вecь~ полезно ЗJlЗТЬ~ что происходит "за кулисами",

Полезным "цобочным эффектом" раБOТbI с С$С .ехе ЯВЛfle"F(,"R ТО, ЧТО ~ будет
проще ИСШЩВЗОВаТЪ .цругиеинструменты JtомацднОЙ стро:ки. ВXDдящ;це Б НоМIlЛetn'
nocтaвlUl .NIЦ Framewo, k 2.0 эок В лроц~ссе изучения :материала этой ~И вы
увидите . что. МQGГИe очень важНЫе утилиты ОЩlЭ!JВаются: ДОСryIПiЫ TOДЬНQ из во­
мmщвой странн.-

Настройка компиnsrrора командной строки ДIUI С#


Чтобы ИЩIОJЩЗO;вать RОМПИЛЯТОР к.омандв.ой стРОlt,И для O~> нужно, чтQБываша
система, мота ~ти файл 'С8С.ехе. ECQIИ машина сконфигурирована 1Jещ>8впль­
но, то JIP~ RОМПИЛЯЦИИ файл{)Б С# Ba..t.I придется указать полный цуть J(, фащ
cSC;.exe.
чтоБы ~И;С~ могла1tOМIIilJIИраза1JЪ файлы "'.св ~дюбого:ка.тaJlQra. рЫnолните
еледу:ющи;е шarи (они соответствую'!' установке ,Б Windows ХР; в Wшdaws NТ /2000
эти ШaI"И буЦV1' аналоtичНblМИ).

1. Щeлкюrre па nп.юограмме Мой Компьютер и выберите пункт Свойства из рас·


КРЬПШIеrocя КЩl"I'е~стноro меню.

2. Вы~ите ВIOIЗ.ДJ(y Дополни.телыщ и щелкните на к.нОПRе Переменные ореды.


'3. Двойным щелчвом iUt uмe~щ ~емешlOЙ Path в окне Системные переменные
откройте о.кно ее ИЗМенения.
82 Часть 1. Общие свеДения о языке С# и платформе .NEТ

Если все было сделано правильно. вы должны увидеть список опций настройки.
ПО)1ДеРЖJШаемых компиляторОМ С#.

Замечание. В списке аргументов командной строки для любого средства разработки . NEТ в каче­
стве разделителя можно использовать - или I (например, csc -? или csc I?) .

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


До начала uсполъзовашш csc.exe добавьте в сuстемную переменную Path сле­
дующее значение (снова не забудьте проверить правилъностъ указанного пути).

С: \Program Fl1e.s \ Microsoft Visual Studio 8\SDK\v2. O\Bin


Напомним, что этот каталог содержит инструменты командной строки. которые
используются в процессе разработки .NЕТ-приложениЙ. После создания двух уна­
ЗaшIЫХ путей поиска у вас должна появиться возможность выполнять любую ути­
литу .NEТ из любого командного окна. Чтобы проверить правилъность внесенных
изменений, ЗЭRройте все открытые командные окна, затем откройте новое команд­
ное окно и введите в нем следующую команду, поэволяюIЦYЮ просмотреть опции

утилиты GAC. gacutil.exe.


gacutil I?

Совет. Теперь вы знаете, как вручную настроить свою машину, но есть и более КОРОТКИЙ nyn,.
Среда .NEТ Framework 2.0 SDK предлагает уже сконфигурированное командное окно, рас­
познающее все утилиты команДНОЙ строки .NEТ Используя кнопку Пуск, выберите из меню
Все Программы~Мiсгоsоft .NET Framework SDK v2.0 и активизируйте строку SDK Command
Prompt (Командная строка SDK).

Компоновка С#-приложений с помощью csc.exe


Теперь, когда машина распознает csc.exe, с помощью компилятора командной
строки С# и программы Блокнот мы построим простой оДНомо.цульНЫЙ компоно­
вочный блок. который назовем TestApp. еке. для начала нам нужен исходный код .
Откройте npограмму Блокнот и введите в ее окно следующее.

11 Простое Dpиnо_ние на HSWJCe С#.


using Sy stem;
class TestApp
{
public s tatic vo i d Main (J
{
Сопs о lе.Wri tеLinе("ПРОЕерка! 1, 2, 3");

3аверпnm ввод. сохраните файл с именем TestApp.cs в подходящем месте на


диске (например, в каталоге C:\CscExample). Теперь рассмотрим основные оlЩИИ
компилятора С#. Прежде всего нужно понять, кан: указывается имя и тип создава­
емого компоновочного блока (это может быть. например. консольное приложение с
именем MyShell.exe. библиотека программного кода с именем MathLib.dll, при-
[лава 2. ТеХН.ОJlОIИЯ со~даlН4Я прило*еНI4Й ",а ЯЗ1>lке С# 83
ЗIожеице Windows F01J115 с именем 'М~W.inАрр. ехе и т.д.}. Raждан. из .возможностей
обозначается соответствy:IOЩ-ИМ флатом, передаваемым в са с . ехе в виде ОПЦИИ ко­
МaвдRой строки (тl:Ifiл.2-.2).

Та6лица 2.2. Опции компилятора С#, укаэыцющие выходные лараматры

ОnциSl Onис~ние'

!out Используется Дnя указаНИR имеtМ СОЗДавае",рго 'IЮМПОRОВО'Jt~ого бло·ка.


ПQ умолчанию имя КОМIТOкОВОЧНQГО блока coвnaдae, с иl,tekем исходного
файла'" .СВ (в. СЛУ'Ш6 ". ·d ll) или с имвмем типа, содержаЩеiО метод
Mai г. () програММрl (8 СJ1учае +. ехе)
lt a l'get ~ ехе Иопользуется ДI1я создщ~Ю1 It:ОНСОЛЬКОГО ~Л(})ltения , ДанНЫЙ тип 8i;1Jl:OA-
НОГО файла подразумевается П'О УМОЛ''1ЭНИIO, поэтому ЭТУ опцию при nQ-
строении КОНСОЛЬНОГО приложения NlОЖНО ОПУ.СТИТl'

tt'aJL-gеt ~ 1 ibIar~' Используe-rся для ПОDтрое~lИgОд.ном(щУлЬногО КОМПЬНОВОЧi-JОГ(!Jблока '*. dll


!target :JnQdцlе' ИспоЛЬЭуе;rся дnя ПQС'Т'рtiJВНИЯ MPAYfI!'!, МодулLo1 Rвляmся составляющl'IМИ
MHorOMOAyJ1I;.HbIX компоно8Qчныx блоков (см. главу 11)
/t arg,et: wi,~e'Xe ПриложеН14я Window5 МОЖIФ строить и с пемощы() фд~п~ I ta r:get: ехе.
не флаг l t a rg,e t;winexe исключает nояlmение ·оict1а l(О~СОДИ в фоно­
вом режиме

Чтобы скомп.и.лир .Qватъ 'Ге $t Ар Р .с$ в консольное прИ.J1DженЙ'е с именем


Text.App~ еКе . переii,п;ите в ЩlТ~ОГ. соле.ржэщиti файл с исходным кодом . и введите
следУЮщую строку комщ-щ {обратите внщ.щние ЦЕ:} ТО, что флar'и командной стр<ЛCli
должны бьrrь указаны ДО IiМeJi ВXQAНl;dX qщйлод, а :щ~ после).

еэС Itarqet~exe 'I'б"st.Aрр. с:s

Здесь не указан нв:В:о флаг I out, tlОЭ"I'Ом:У :выполняемый фaiiЛ будет На3ЩiН
т e.s.t-A р р • е х е. поскольку 1tJI.aCC. :определяющий то~шу Юi:ОJ1;а прогрзммы (метед
Мai-n (,) , у наОШЩЬЦ'iается ТеБtAр,р, СледУеТ знать о том, 'iТO почти все флаги }(()М­
ПИЛiIТОра С# :И:МЩОТ СОКJmЩeн1:iЬ1е версии написания, Например. МОЩНО исдолъзЬ­
ватъ !t 1il\iCCTO /tar ge t (:все сcmращения мо}КНо увидetъ с помощью ВЩЩ8 еэс /?
в командной (:трi;>ке).

'С 'В ::: I t: аха TestApp, са

1{ тому же, поскольку флаг / t : ex~ опред~ет вывод, испо.п:ъзуемblЙ 1ЮМ1:mmrrCl ~


рОМ С# no УМОJ1'I8.lIИ1O. ДJШ компиляции 1;es tApp. c.$ можно использовать след1Ю~
щую простую строку.

<:;3:'с Test_A.pp. сs

Рис. 2•.1. ПРl'1ложеНL<tВ TestApp. в действl'lИ


84 Часть 1. Общие сведения о яЗЫке С# и платформе .NET

Ссыпки на внешний компоновочный блок


Теперь выясним, как компилировать приложение. использующее ТШIЫ. опреде­
ленные в отдельном компоновочном блоке .NEТ. Здесь. чтобы было ясно. почему
при построении указанного выше приложения компИлятор С# понял ссылку на тип
System.Console. следует вспомнить о том (см. главу 1). что ссылка на mscorlib.dll
при КОМПИЛЯЦИИ предполатается aвmoмamuчeСICU- Если же по какой-то особой при­
чине Э'ry' ссылку необходимо отключить. следует использовать флат /nostdlib.
Чтобы иллюстрировать механизм ссылки на внеIШIИе компоновочные блоки, мы
модифицируем приложение TestApp так, чтобы оно отображало окно сообщения
Windows Fbrms. Откройте файл TestApp.cs и измените его следующим образом.
using System;
// Доб. .~~е это:
using System.Windows.Forms;
class TestApp

public static void Main()


(
Сопsо1е.WritеLiпе("Проверка! 1, 2, 3");
// ДобаВ~'1'е это:
МеssаgеВох.shоw("ПриВеТ ... ··) ;

Здесь с помощью ключевого слова using С# (см. главу 1) добавлена ссылка на


пространство имен System.Windows.Forms. Напомним. что при явном указании
пространств имен. используемых в рамках файла *. сэ. нет необходимости исполь­
зовать абсолютные имена (рукам легче).
В командной строке компилятору esc.exe следует сообщить о том. в каком из
компоновочных блоков содержатся Киспользуемые" пространства имен. Так. при ис­
пользовании класса MessageBox с помощью опции /reference (которую можно "со­
кратить~ до /r) следует YIсазать компоновочный блок System.Windows.Forms.dll.

csc /r:Sуаtem.Windоws.FОЖ'IDs.dll testapp.cs


Если теперь снова выполнить наше приложение, то вдобавок к вьшоду на кон­
соль вы должны увидеть окно. подобное показанному на рис. 2.2.

ПrМIeт ...

Рис. 2.2. Ваше первое приложение Windows Forms


Глааа 2. Технол~г~ясоздаНИII ПРJ,мо,женкй на языке С# 85

КОМПИЛflЦИR множества файлов


в данном варианте придожение TestApp. ехе использует ОДИН файл и:рходнего
кода *.сэ. ВПQлне:возмож:но, ч:I!об:ывсе пmы .NET-прилОжеНИfl были пред(:т~ны
в. Oд:QOM файле ".СВ. ВО болыIIинтво Щ>оекТ(JВ :комдо1iYетсниз множества фаЙ/JОВ
'* .С;5, Ч1i'Oбы npoгра.ммньЩ код был более rиf5IЩМ. СщщзйтеlJDВЫЙ класс и помести­
те еro в DТделъиый фa:йJ;J HeHoM5g.CS.
11 ltIIacc Beи~aaap
lJs.i:ng S",'stem;
u.зiлg Sуs'tеrn.lAiпdQW.э .]'ОТпls;

class HelloMessage
{
public vo:Ld speak (:)
{
Мessag'eBox. S,how ("I1ривет ... ") ;

Теперь обновите исхоцмый клаGC '1'estApp так, чтобы в ые;мисПOЛhЗOВaJ'1СЯ этот


tIQВblЙ nЩ. а предыд.УЩУЮ логдку Windows Ebrms закоммеьrrиpуЙге.

uзiг"g SY5tent;
/ / Э~ бom.sae не ~буе!l.'cJa:
11 цsinq Syst&il1. Windows. FоЩ8 ;
сlаэs Te'stApp
{
publ l cstatic void Main()
{
СОЛ S<'Jlе.Wri ,tе'Linе ("оро:вер.ка! 1. '2 ( З");

1/ и $'l"Q '\\'O_ ,~
11 ИеsааgеВох. $ЬОМ, ( "Приве~ •.. ") ;

11 Ис,аom.sоаание JUIacca B.,I lolfe,S 8aqe:


НеllЬМезsаgе h = 11,ew Hel1oMe~~age (} ;
h. Speak. О;

С1(омцилируйте эти фaйJ'Ibl С# С UО1\1JDЩbЮ их явного укаащmя в качеСТве мод­


lЩX, фа:й,.rl()В.

С.БG: Ir :SY5tem. Wi1rldows . Forms .dll t •• upp.cs h~~OIUq. С8

В качестве адъте,рнативы .компилятор С#' прзвоrшет ИОПО:1IЬЗоватъ груцповей


символ '("}. ИНфОРМИ:РУЮщиi ('J 5с. ехе О том"ЧТfi) следует Вitлючиn. в тецущий про­
eк:r все файльr .. . ~a. содержащие~я в naпке npoекта:

С5'С I r ;s.yste.m . Windows. F.опщ;. dll .,.. са


Резу:lIЩ',ат выnoлнеmtR НОВОЙ црограмм.ы не буде1'Отличать.ся от предыдущего,
EдmrСТВdНJП:ifМ отличием 3Т1-1ХДВУХ npиложений бу~ Т<ЩЬКQ ТО. что тenepb исхо­
Jwый код разделен на два фай.ла:.
86 Часть 1. Общие сведения о языке С# и платформе .NET

Ссылки на множество внешних компоновочных блоков


в связи с рассматриваемой темой возникает следующий вопрос: "Что делать,
если при использовании с s с . е хе нужно сослаться на множество внешних KOM~

поновочных блоковТ Просто перечислить все компоновочные блоки, используя в


качестве разделителя точку с запятой. ДJI.я рассмотренного выше примера не тре­
бовалось указывать множество внешних компоновочных блоков, но вот соответ­
ствующий пример.

ese /r:Syatem.Windowa.Forms.dl~;Syatem.Drawinq.dl~ *.еэ

Работа с ответными файлами csc.exe


Очевидно, что при создании сложных С#-приложекий из командной строки
было бы очень неудобно набирать ВРУЧЦУЮ все флаги и ссылки, необходимые для
указания множества компоновочных блоков и входных файлов *.cs. Чтобы умень­
шить объемы ручного ввода. компилятор С# допускает использование ombe1TU-lblX
файлов.
Ответные файлы С# содержат инструкции, которые бу1JYТ использоваться ком­
пилятором в процессе компиляции входного потока. По соглашению это файлы с
расширением *. rsp (сокращение от response - ответ). Предположим, что вы соз­
дали ответный файл TestApp. rsp. содержащий следующие арryмеиты (как видите.
комментарии в данном случае обозначаются символам i).
,. Э'1'0 оorвеor1UolЙ ф&й'n
# д;n:_ Теа tApp. ехе иs ГЛaJIlol 2.

• СCIoIЛХИ на внешние ItОМnОНОВОЧНlolе блохи:


/r:System.Windows.Forms.dll
,. опции BloIВoдa и ф&Й.JDol дn_ ltоМПИJIRЦИИ
# (здесь испольsуеorс_ групповой символ) :
/target:exe /out:TestApp.exe *.cs
Предполагая, что QТOT файл сохранен в каталоге с компилируемыми файлами
исходного кода С#. мы можем построить наше приложение с помощью команды.
ПОRазанной ниже (обратите внимэ,ние на использование символа @).
ese @TestApp.rsp
При необходимости можно указать несколько входных файлов *. rsp (скажем,
ese @FirstFile.rsp @SecondFile.rsp @ThirdFile.rsp). При таком подходе
следует учитывать то, что компилятор обрабатывает командные опции в порядке
их поступления. поэтому apryмeHTЫ командной строки в последнем файле *. rsp
могут "переопределить" опции предыдущих ответных файлов.
Учтите и то. что флаги. указанные явно в командной строке до ответного файла,
будут ~переопределены" теми флагами, которые будут указаны в соответствующем
файле *.rsp. Так. если вы введете

esc /out:МyCoolApp.exe @Testf\.pp.rsp


Р1ава 2. Технология СQздания ПР.ИЛОЖ{JНИЙ НIi 1\'3),11\6 С# 87
то именем :КОМI101'lовочноroблона псе равно будет Tes:tApp.exe (а Не MyCoolApp .еХ$).
пO€;кольt,ty 11 oTBe:rнoм файле Te.stApp.l'Sp ук,ащш фJiar /out :ТеstАрьц~.хе. Но еGЛИ
УШ13ат.ъ флш пос:ле ответного файла. то уже флаг ОDЮНИТ опции ответного фail:лa.
.1
ТаЕ, в результате выполнения ·сдедующеЙ "Команды КО1liПIОВОБО'<tНb1;Й бло:к получит
I
имя MyCoolApp. ехе.
С'ЗС @'I'e-<;:tАрр.rsр /out ;1!fyCoolApp. еже

замечанке. Флаг /reference Я'J;lЛЯЕПСЯ J<YМYЛЯТИВНЫМ . Н6за8ИС~МО ,от того, где вы укажете
внешние ~омnрнов0чныБл\).I(ии (до,. :ПОDле ИЛL1 8~УТРИ о,-вет.ного файла). результатом будет
обьедйненwв- всех ССЬiJIОХ.

Ответный фам, используе, мый по умолчанию (osc.rsp)


БотнощeнIЩ ответныХ файлов CJIeдyeT ;mать то, Ч'ГО ком:пилыор с# Юvlеет OT~
Вe'J1НblЙ файл, используемый по умолчaнmo,. э-roqщй.J:r еэс .EBp~ размещенный в ТОМ
Ж8 kЗТaJ,Iоге. ч"то и СЗО.е х е (соответствующим каталогом может быть. например,
C:\Wlndows\.1'1icr9BCoft.NET\ Fr:amewDtk\v:2.0. 50215). Если oтъ.-pьrrь файл с:в с.твр С
помощью npогрЭмм:ы 'Блокн.от. вы УВIfЦИТ~. ЧТО 11 ~eм: с помощью флага / т; уще
yr<aэa1-I це;IJЪШ набор RОМI10НQВОЧНЫ" б1JOlФВ ,NE'J:
Прц КОЩПОl;f911RС С#-npоrpаммы с помощью ,: :sC;: .6.xe ·ccъmкa на этот файл В1.!-­
полн.цется автоща'I1ИЧесхи. даже кОГДа вы ytWЗЫЩLe<l'С СВОЙ файл *. r эр, С УЧ~ТОМ
ответного файла. испол:ьзуеМQГ(J ПО умолчанию. наш~ приложение Tes tApp.e;xe бу­
детycnennro скоМпилировано и при ИСПQJIЬ30в-a.-щцJ СJщцующей команды (ТЩ< IЩ1f в
csc.rsp есть С()ы1П~а на 'System .Windows.J'orms .d11).
с &С i G bl t ; Tes.tApp . е1{е ... . С5
Ec1nr НУЖНQ 01"КЛЮ'ПJТЬ авТQмаПJЧеское чтение файла cS{: .rs p. CJ1eдyeт указать
ОIЩИЮ /т!Осолfiщ.

С5С @1;est-App. rsp /noconfig

ltомпиля.трр командной стрОRИ С# ~MeeT мвощество друтих оПnИЙ. кoтopы~


можно цсполрзQiз-ать ДЛЯ управления пр:оцессом генерирования RОМ:ЦОНОВОЧнЫХ

блоков ,.NEТ, Если вам требуется более подробная 1Цlформация о функцианальныx


возможностях csc.e-ке.11рОчитайте мою статью ~Wогldпgwith the С# 2.0 СОПШlапd
LIne CompЦeг~ (Работа с JiОМlIИЛJJТОРОМ tl;оман:дщэIr CTpi1IOI С# 2.0). которую монщо
1ЩЙ:rИ на страницах httр:/ lmsdn.щiСI Q5 0ft.сот.

О'тладчик командной 'строки (cordbg.exe·)


Прежде -чем переЙТ!I R раССМDТpеJШЮ возможностей :КОМIlОЦОВКИ C#-iIрил:оже­
ни:й с помощью ThxtPad. слецует отметить. что .NEТ Framework 2.0 ~DК пре.цлаг,а­
ет ()'DlaДЧИR }{ОМaндlfой строки c;:o.l·dbg .exe. ЭтотинструмеI-JТ имеет ЩIQж.ество оп­
ЦИЙ, которые uо.зволюот ВЬДlолнить OTlI8;II;Кj' I<т.ШQповочноtо бдока:. "'ITO(5bl увццеть
епвсо:К эт.их arший. ИСnОJIPзуЮ-е фщ!г ./?
.cotdЬQj n
88 Чаоть 1. Общие сведения о языке С# и ~латформе .NET

в табл. 2.3 ПOlсаззны некоторые (но. конечно же. не все) флаги с указанием их
сокращенных форм. раcnознаваемые отладчиком cordbg. ехе в сеансе отладки.

Таблица 2.3. Некоторые флаги командной строки отладчика cordbg .ехе

Флаг Описание

b[reak] Установить или показать текущие точки останова

del[eteJ УдалИТЬ одну или несколько точек остановв


ех [it] Выход из отладчика

g[o] Продолжить отладку текущего процесса до следующей ТОЧI<И останова

о [ut] Выйти из текущей ФУНI<ЦИИ

р [rint] Напечатать все загруженные переменные (локальные, аргументы и т.д. )

si Войти В следующую строку

so Перейти через следующую строку

Большинство из вас предпочтет использовать интегрированный отлэдЧШ( V1sual


Studio 2005. поэтому я не собираюсь комментировать все флаги c;:ordbg.exe. Но
для тех. кому это интересно. в следующем разделе предлагается краткое пошаговое

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

Отладка с командной строки


Перед началом отладки приложения с помощью cordbg.exe следует сгене"
рировать отладочные символы для текущего приложения. указав для csc.exe
флаг /debug. Например. чтобы сгенерировать данные отладки для придожения
TestApp.exe, введите следУЮЩУЮ команду.
esc @testapp.rsp /debug
В результате генерируется новый файл. в данном случае с именем testapp.pdb.
Без соответствующего файла *.pdb использовать cordbg.exe тоже можно, но при
этом в процессе отладки вы не сможете видеть исходный код С# (что, как правило,
важно, если вы не хотите усложнять себе жизнь чтением программного кода CIL).
Сгенерировав файл *. pdb, откройте сеанс отладки. указав для cordbg. ехе свой
компоновочный блок .NEТ в виде аргумента командной строки (при этом файл
*.pdb будет загружен автоматически).

cordbg.exe testapp . exe


Начнется режим отладки. и вы получите возможность применять любые допу"
стимые флаги cordbg.exe в командной строке (cordbg) (рис. 2.3).
Чтобы выйти из режима отладки eordbg.exe. следует просто ввести exit (или .
сокращенно. ех). Если вы не являетесь стойким приверженцем использования ко­
мандной строки. вы предпочтете использовать возможности графического отлад­
чика. предлагаемого интегрированной средой разработки. В любом случае для по­
лучения дополнительной информации обратитесь к разделу в документации .NEТ
Framework 2.0 SDK. посвящешfOМУ cordbg.exe.
Г71вва '2.. ТехнолоNtи еоздэнн!! nри.nажениЙ на языке' С# в9

,1

РИс. 2 •.3. Оm8ДКЭ nрИ'ложеliИR [) ПОМОЩЬЮ cordbg,exe

Компоновка .НЕТ -приnожений


с помощью TextPad
Бесп.i1'атНJ:iI;Й редаRlТQР БлоКRО~ neco1l(ReRИo. подходит;цля создания простых
прОl',РаММ .NEТ. :tш о;н не может ничего предложить ДJЩ повышения. nponзводителъ­
H~n 'труда рщ!работ'чИКЗ. ХОрошо. кorдa peдaI<ТOp . ~ ПОМОЩЬЮ которого создают­
ся файлы '*. СЭ. поддерживает (lt.aR М~) .вьщедение цветом ЮnOчевых СЛОВ 1!I
блопов npoграммного .хода. а также предлагает :интеtрaдmo с компил.ятором С ,#.
1Цщ и ~eдYeT ожидать. такой ин:струмеиr еуществу~т-' Это'ThxtPаd.
Редактор 1eXtPad можно использовать для созд;цrnя и компиляции програм­
мцоro кода HeTOJIЫro на яro.rкe С#. но и М}.1QrИX; друI:ИX яаьшах hpоrраммироВЗ1lИЯ.
Dta.внoe пр~~ес:tво этого 11pOдV1(ТЭ. заключается в тои, что он. с ОДНОЙ стороны.
очень пр()Щ' в иcnom.эовamш. а с дРугой - обеспечивает ДDcтaTo~HO широкие воэ­
МОЖЩ1СТИ для упрощения процесса ооэдания програм:много вода.
ЧтоБЬ! шmучить Te.xtPad. перейдите на стрa.н:иuy http~ I /www. textp~d, сол\ и
загрузите текущую версша этого peдaRТOpa (во время с(')здaiIи.я нашей КШIr8,Щ'О
была версил 4.7.3). Установив ЗТО"1' редЗIqQР. вы сразу получите полноценную ,вер­
сию 1С1Шl'ас:1, с .поJIFi:blМ набором е!'о ВОЗМQЖНОСтеИ. J-ю3НаЙте. что ЭТОТ продукт не
бесдлатен. Пока вы не иynкге лицензию (ее OТOllМOCТЬ окало $30 ДЛJi одното П(!)ЛЬ·
аовil-rеля:).:вы будете видеть "дружеские напоминания- npи 1iWIЩОМ запуске ЭТОГО
JIpИ!I,ожеНИя.

Активизация цветовой схемы С#,


ИВЩ!чRлыrо редактор ThxtPad не настроен fЩ .ao~ КJIlC\чевых CJЮв С# И РаБО1У
С РВС, еже. Чтобы настроиrъ ero СОoтвeтcтвyIOЩШ4 образом, нужно устэ.НOIЩТЬ ~ДXO­
дmцee расширенИе. Orкpойте crраницуhttр~1 /WilW .textpao., com/aM-ons/$УI19.~g .html
иза:грузите фэйJ.I osharp.8.,zip по ссылке С .. ~005'. Соответствующее расширение
90 Часть 1, Общие сведеttия о языке С# и платформе ,NET

учитывает новые ключевые сло:еа. :е:ееденные в С# 2005 (в отличие от файла, загру­


жаемого по ссылке С#. в котором учитываются только возможности С# 1.1).
Развернув архив с shаr р 8. zi р. поместите копию извлеченного файла
csharp8. syn в подкаталог Samples каталога инсталляции Thxtpad (например. в
C:\Program Files\TextPad 4\Samples). Затем запустите ThxtPad и с помощью
New Document Wizard (Мастер создания нового документа) выполните следующие
действия,

1. Выберите ConfigureqNew Document Class из меню.


2. В:еедите имя С # 2. О в поле редактирования Document class пате (Имя доку­
мента нласса).

3. Затем в:еедите *. cs в поле редактирования Class members (Члены класса).

4. Активизируйте подсветку синтаксиса, выберите csharp8.syn из раскры:еаю­


щегося списка и закройте окно мастера.

Теперь вы можете настроить поддержку С# в 1extPad. используя узел Document


Classes (Классы документа). доступный из меню ConfigureO::>Preferences (рис. 2.4).

General optlo".'
Fie •... ---------.
j-.a
o MaII1Iain indent~on
Ed;tor ; {. . . . . . . . . . H . H . . . ~
'11
О A!tomatic<li!ynder1l Ь1ООО
, О
О
Indude tri>i!ing 'Расе. when SeIeCtirJ<;j
SIлp trallI'1g орасео from lIneO when
D.efautt I '
ltl I ! О ''\е.. irt ,"еь browser
, i
[~ Бi""'У' О Wnt. lJr;CO<Je and UТF·I!ВOM
I :
it1 u.nmand R_ О Word wщ> 10119 .,..
;tj SeO!Ch
I
.
'

~ \Vord"""PPed te>:l
.I I
(±J С#
с,,_ !
I
I
oSave.,dh по I>re;!ks in hne.
1 О Save WitI1 haro b!eak.
Cola~ I
~ Check speIIlПg af:
Fant
PJinting
Synt""
Tabuiatibn O!tloro Ьм"" aI COUm ~ [[]
гfi с-с- Dlwtt1hese !~I<>" ~ daua
iiJ J.ПМL у"
ОК )1 ~]

Рис. 2.4. Установка параметров редактора TextPad

Настройка фильтра файлов * .CS


Следующим шагом конфигурации является создание фильтра для файлов ис­
ходного кода С#. отображаемых в диалоговых окнах Ореп (Открытие документа) и
Save (Сохранение документа).

1, Сначала выберите ConfigureO::>Preferences из меню. а затем- элемент File Name


Filters (Фильтры имен файлов) дерева про смотра.

2. Щелкните на кнопке New (Создать). а затем :ев едите С # в поле Description


(Описание) и * .cs в текстовый блок Wild cards (rpyrшовые символы),

3. Переместите свОй новый фильтр в начало списка. используя для этого кноПI<у
Move Up (Вверх). а затем щелкните на кнопке ОК.
ГЛi\ва 2" ТеХliО1JОГИЯ СОЗАани~ приложений на языке С# 91
Создайте новьrй файл (испоцщуИте Flle~New} 1J 'сохраните его в, подходящем мe~
сте на ДИСl(е (например. в пашю
C:\'1extPadTestApp) Щ)Д Нменем ТехtРаd'I'еs,t.СЭ.
Затем введите тривиалыюе onредerrение хласса (рис. 2.5).

class Progpm
(

CottэQle.writeUne("Н.?;J,.... UDfl1 Te.'ct}'Ii!.;"r.


~.Re.i.:!l1n!!\,!:

РМС. 2.5. файл TextPadTest.c-g

ПОАключение csc.exe
Последним дз основпых m:a:гoB RoRфиrypации PMaI<ТOpa TextPad будет связь с
еве .ехе. которая поэвол;ит КОмnи.iШpоватъ с#~файл:ы. с этой Ц~ МОЖНО. напри­
мер, выбрат'ь ToolsQRun из меню. Вы увидите диалOl~овое OЮIQ. lЮторge позвОлит
унааать ИМЯ соответствующей npoI]>a.'dмыI и необходимые флarи командной СТрО­
КИ. Тш(, чтобы CK~poвaть TextPadTest.c:s в вьmоЩ;tЯемъЩ RОНСО.п:ьиый файл
.NEr, выпо.IIНИJ'e CJlедyющnе marи.
1. Вве,ците ПОJII;{ЫЙ ПУТЬ к файлу свс.ехе в текстовое поле СоmrТlC!пd (Команда).
например С: \Windоws\Иi c-rosoft .NEТ\Frarnew6rk\v2. О .502И\сзс.ехе.

2. НеОбходимые опции 1roМatiДНой строки введи'rе в текстовое поле Parameters


(Параметры)-нanрпмер. /otJt:myApp.€xe ~ ..cв. Дляynpощ~ния npoц~cca
настройки МОЖ1Ш ужаэать O!Г.вeтныji файл (например, @rnyInp.ut.rsp}.
3', В ТCRC1"QBOM Поле Inltial folder (Исходный ~~TaдDг1 y:кaжiI"re ldiTailOt, содержа­
щий входные фaibIы {для нашего ПРЩdера это C;\Te-хtРаdТе5tАрр).

4. Если вы XQтите ,. чтобы редактор Thxtpad Зах.Батьтвал BbIВOД КОМПИJIлтора


(а не цщщзывал его в отделЪ!юм командщ:>м ОRJЯе). уе.тзнови:.re флажок Сэрtuге
Output [Захват вывода).

На рио. 2.61юltазаны все необходимы;е ДДН нашеrо цримера установки компи­


ДfЩИИ.
92 Часть 1. Общие сведения о языке С# и платформе .NET

Run I:EI
~~ ;@\W~S~.~Ei\~Z;21
br,,-.:~mylw.-·~ .--- .. -- ]
....·f...·, 'jC:\TIOdPadTeot1Q:> J
OIP~c.1i;".rd 0~1!!*
Da..t.OOS ......... an . . D~~

I ОК J( ~ I [ е.... ]1,--J:leb---'
Рис. 2.6. Установка параметров команды Аил

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


имени ее выполняемого файла в программе Проводник Windows. либо с помощью
выбора TooIs9Run из меню редактора ThxtPad. указав туАрр.ехе в качестве теку­
щей команды (рис. 2.7).

Run ~,

~
"--.а:
t;i;p-;';~~-:---~--- -~=-~_ ~
C~ .. ~_~_._._.'::~_-'- ]
. .
1n(jS1!*Ior.. ~\TooctP!ldT~ --~ _О]

D~~ 0CII*W~
Dao.oos ......... ..,_ OfQ1МOnUod

Г of< i j c.пceI I [ I!ra_.. I Г!-:Нojp~--'


Рис. 2.7. Указание редактору TextPad запустить туАрр.ехе

После щелчка на кнопке ОК вы должны увидеть вывод программы (MHello from


ThxtPad"). отображенный в документе Command Results (Результаты команды).

Ассоциация команд с пунктами меню


Редактор ThxtPad также позволяет создавать пункты пользовательского меню.
представляющи:е заданные команды. для выполнения компиляции всех С#-файлов
в текущем каталоге мы создадим НОВЫй пунит меню Compile С# Console (Консоль
компиляции С#) в меню Tools (Сервис).

1. Сначала выберите Configuгe~Preferences из меню. а затем- элемент Tools де­


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

2. С помощью кнопки Add (Добавить) выберите Pгogram (Программа) и укажите


полный путь к csc.exe.
З. Вместо еБе. ехе можно указать для меню более информативную строку. - на­
пример Compile С# Console. - щелкнув на соответствующем имени. после
чего следует щелкнуть на кнопке ОК.

4. Наконец. выберите ConfigureqPгeferences из меню еще раз, но на этот пере­


йдите к элементу Сотрilе С# Console узла Tools и укажите значение *. СБ в
поле Paгameteгs (Параметры). рис. 2.8.
r
Глзвй 2. Технология СОЗА8ИИЯ 'nРИJ1OJкеflИЙ 118 яаJ,lке С# 93

O~fer-,-"" 0с.,. ....


OIbl'--..кI Dщ.р...OIIIU~-""'"
OS-4 ............... 0S01.N *1 whm CII СМ d

, ]

еж

Рис. 2.В~ СОз,цaнJIIEl эnеме,нта MeHIO Тооlэ

Т~перь вы получите возможность компилировать все файлы С# из те«ущего }Цi­


ТaJщга с помоЩью нового пункта:меню TooIs,

ИСПОЛhЗ0вание фрагментов программного кода С#


Перед ИСШШЪЗ0в<1нием 1extPad следует упомяну-тъ еЩе 06 одном бееnлатво:м,
рзсшИрений. которое ВЫ можете установит~. Перейдите на с-rpаницу ht tp: 1/
ww:w.tex-tраd. , соm/аdd-CII1э/сl1рliЬs.Ьtm,1 й загрузите фaЙJt с.эhаrр _l,zip с
библиотекой фрагментов C;/t. доторую дредлагает ШОН Гефарт (Эеап Gephardt).
Извлеките иа архива файл с: s h а rp . t с 1 и поместите 'этот файл в поДКаталО}'
Samples. Снова запус~ ThxtPi:td. вы обиэfJYЖm'e новую бибJ1ИОТ-еку фрЩ'М~нтов
nPО1'р8ММ1rого IФда С Sharp Helpers, ДОС'I'Упную из рас:крывающегося списка Сliр
LiЬгагу(БиБЛlIотека. фРCU-ментов), рис. 2.9. С ПОМDщьюдвойвоro ще.лчка lЩ любом
из ее алемен-tов вы мож~ге доб~11> соответCТIiующий пporраммный lЩД С# :в той
wчне .aRrИБноrо докумеI;lта. r,цe в f{Щ':ТР.ящий МОМеНТ находm;ся курсор,

Рис, .2.9. Фрагменты npbrpaMMHoro kOдa с# В TextPad

Наверное, вы не станете возражать. 'iJ"O 110 срзвtЩНИЮ с программой Блокнот


и RОмандн:ой етpakОЙ испольэовauие ред.антора "Ib."tPad- шах в прави.льном на­
правлении, Однако ~t:Pad (пока что] не ~ДJIaТaeт ВОЗМоЖ1-iОС-ТН IntelliSen~ ДДЯ
.

94 Часть 1. Общие сведения о языке С# и платформе .NET

программного кода С#. графических средств разработки, шаблонов проектов и


средств работы с базами данных. Чтобы представить такие ВОЗМОЖIЮСТИ, рассмо­
трим слецующий инструмент .NЕТ-разработки: SharpDevelop.

Компоновка.NЕТ-приложениЙ
С помощью SharpDevelop
SharpDevelop является интегрированной средой разработки с открытым ис­
ходныIM кодом И богатыми возможностями. которые вы можете использовать для
создания компоновочных БЛОRОВ .NEТ на основе С#, vв .NEт, Managed Extensions
для С++ или CIL. Кроме того, что эта среда разрабоТRИ совершенно бесплатна,
следует отметить то, что она ЦeлиRом создана на язьmе С#. Причем вы можете
либо загрузить и СRомпилировать необходимые файлы *.сэ самостоятельно. либо
использовать готовую программу setup.exe, RОТОРая установит SharpDevelop
на вашей машине. Оба дистрибутива можно загрузить со страниц h t tp : //
www.icsharpcode.net/OpenSource/SD/Download.
После установки SharpDeveJop выбор меню Fileq NewQ Combine позволит указать
вид (и язык .NEТ) проекта, который вы хотите создать. В терминах SharpDevelop
сотЫnе (Rомбинат) обозначает отдельную коллекцию проектов - то, что в Visua!
Studlo называется
solutiOn, 'l:e. решение. Предположим, что вы указали С#-прило­
жение для Windows и назвали его MySDWinApp (рис. 2.10).

N",w P r O j E ' C ! ' IХ I

i'iindow. Se<vice

-- ~ - ~ " ' ~--- - ~ -~. ". ~ -- -- ~ - ~ - ~- ..


~ .~~ ". -~~~ .- -',.......~~ ," ."--"-,~ - .
-~- ~",.

•АрЩect that crates JO!\ 5PPI.<:ation with 8 \>J!t'odiм" inlelfllC~.

location:E\~';";.'~
-.< -_.
s~~\~~;J$eпl~ТЕRтЕсff~~"i~j CJ
......... ...... . _ ... ..
Г"" ~

Ne>Ii Pmiect Name:LМy_~1?~~ ~_ ~_! О Cre?Jt. <hdщ foг sout:es


o >цо create l>f'Ii!Id lIЫir
Project wШ ье creafed at СА. ,\МJi Documertllt\5МqJOevгk>p ProjeoIs\Мy$Q\"'~

Рис. 2.10. Диалоговое OКliO создания проекта в SharpDevelop


1
Г~з.ва 2. Те)(flOЛnГИЯ создания ПРI1J1DЖ&FlИЙ на flзыке С# 95
J
ЗаМe>tа~ме. приложеЮ1е $tlафI;)еvеloр S~РGИ~ 1.0 наС1:Роено на ИСПОi1ьзоваНйе kомпиЛ\пора
С# 1.1 . Чтобы испадьэова-ть новые ВQЗможнооти языка С# 2005 и прrэстраНС'f8а имен . NEТ
FmmeworR2.0, еы6ери-rеProjectQPrQjecf ,options из менlO и укаЖI11;е НО8;'Ю версию КО~ПИЛ~­
"Тора на страюще настроек Runtime/CompiJer (ерем ВЬ!f1QfI~lения/I<DМп.илятор).

Возможности SharpDevelop
Среда разраБОrrRJ1 SbarpDevelop 'Рр~длШ'ает разНообразные возможности цо­
выmениSl nPОИЗIlОДИТе.лъности труда црограммиСта. и во МНОгих Dтношеаинх эта

среда разрабоТIШ СТОЛЬ :же богата ВQЗМОЖНОСТНМИ. :как и V1S'Ua1 studio .NЪ"Т 2003
lНС1 Н,е наtтолы< •. хщс Visual StшЦо 2005). Вот список OCHOnH~ цреи:муществ
SharpDevelop:
• по,пдержка ношшлнторов С# от' Wcli'osoft и МЬnо:

• ЩIЗr4ШЕFЮСТИ lntеШSensе и раСIlIиpеиин программ:ноro нодщ

• наличие ДИfl.Jiогового окна Add Reference (Доба:вл.ение ССI:ЩRИ) для СС:ЫЛОR ,на
внеmние КOМnOllOВo'lНb1e блоки. включая КомпоноВочные блоки. установлен­
ные в GAC (G10Ьal ЛssешЬ1у СаеЬе - глобa.лbliЬJ:Й F.ЭЦI номnщlОВОЧНЫХ бло:ков)~
• нa.JIИЧИf:' инструмеЩОВ визуальНОГО проектированиц Wfndows FQrms;
• различные онна[в SharpDeve!op, они нaaъmаюТСЯ scouts - развeдчиRИ) ДJ/Я
обзора СТРУКГУРЬJnpoекта и его '.состa:вля::iOЩИX:
• и:НтеГРИРОВlШИaJI утилита браУ3ера объеIC'ГОВ '- Asseтb1y Scout (раз.ведчик
ВОМIIОНОВОЧIIЫX блоков);

• yt'ИJIИ'FЫ Дт.iЯ работы с базами' ДaщlblX;

• угилита .конвертирования прОrp3'ММНОГО ко.да С# в vв .NE1' [и паобоpO'r}:


iI интerр1ЩИ~ С NUnlt (ут:ишгга :rестироваиия .NEТ -модулей) и NАЩ. (У'ТИЛИТ~
RОМПО1iОВю;r. .NEТ);

• интеграция с ДОRYМенгаци~ .N:в."Т Fгamework ЮК

Вnечатлюоще для бесплатной JDE, не так лй? В этой главе мы не собираемся


обсуждать IШ.ЖДЬJЙ И~ yкa~ llУНlПОВ ПОдРОбно . но давайте раССМОТРИМ цаи­
более йН'тереСnЫе из НИХ. Если вас интересуют Dодробпост.и.. то за:мети~, что
SharpDevelop npедлагаеl' очеЩ:! подробную доКументацию. дocтyIIнyJO nPJ:J B~Ope
Нelp<:;>Help Topics И~ меню.

Окна проектов И классов


Создав НОВЫЙ lЮ\I4бинат; lJb! можете иеmшъ:ювать Oltно Projec1.s для nPОQМртра
файлов. ССЫЛОК и P~CYPCOB сооme'i'стцуЮщих npоек'ТоВ (рИС. 2.11).
Чтобы в текущем прое:кте оосцатъсн на, внешний ТЮМПОНОВО'ШblЙ бщж . .в шще
ProJects щелкните правоJ& :кнощщJj щ.mrи на JIИКтограмме Rеtе.геrюеs (СсЬ1lIНИ) Ji из
пшmившегося ко}fl'eКОТИОГО M~ЦP выберите Add Reference (Добавц']Ъ есыnку).l1рсле
этоrо на .8RЛадке GAC или .NET AssembIy Browser (Обзор I(О:Мnано;воЧ!iЫX бло.ков
.NEТ) вы сможете выбрать КОМДОНОВОщп;Ш блок. размещеннЫЙ. coo11Jeтr;ТEeнno., в
ОАС или в дpyJ'QM месте (РИС. 2 . 12)'.
96 Часть 1. Общие сведения о языке С# и платформе .NEТ

Рис. 2.11. Окно проектов

. ~Ye

ок

Рис. 2.12. Диалоговое окно добавления ссылок в SharpDeve10p

Окно Classes обеспечивает объектно-ориентированный взгляд на комбинат. ото­


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

G3 GII MySOWnApp
Gj. lfjJ MySOWnдt<p
s (}~

'·-0
Е! .~ М..nA>nn

• Мiin($tmQШ
;r,. Jri!i8iZ!!C"""""""t.(}

Рис. 2.13. Окно классов


ГЛаБ'а 2. ТехtIОЛОГИ~ СОЭДqния ПРИIIQJkеН\fЙ НЭ gзыке С# 97

I Двойной щеЛ'-IOIi на .любом элементе 01'RPЫВan- соответствующий файл, i1Oме,­


щая X}Ip(:ОР мьпци па определеmre эл~а.

Обзор компоновочных БЛ'ОJОВ


У:гилита: AssernbIy Scout (РазВед~ ~0МПОНОВОЧНЫХ 6ЛОlЮВ), ДOG~ из меню
View. цpeдnaraeT обзор RОМПОНОВОЧНЬЦ бщ:JКРВ, JЩ которые имеютси СCЫJII{И :в про­
екте. Это Gред('тщ> преДlщгает информацщо. н ДВУХ nа;нелях. Левая naнeльпредла­
rae:r дерево npосмотра. П~01IЯЮЩee '"войrи~ ВНУТРЬ RОМIIОНОВОЧНОro блока , чтобы
ущrде:гь Пр'остраl~ства:имен ~ <щответствующие типы (рис. 2. 14).

I "

1
1
:::::
1:1
-"--
QjJ S',"$\"emЖml
· ~. 1'1 SI'Stem:1fтd"tI
i1iI () 5~$'Ii!m
1 ftJ IJ ~ ,COfl1POl"iOrtIМйdel
'W l t W - '
ctl' (J Syslem ,!ImI.~
~ [) S~.)[rnj$~ton
(i f} .&~,xmI.JIP6!!1
• П S _,xn.lJ!",
fji 11 Sf*m.XtN:.~.~
~; . 1 "" I'~ Ш-

r1iI ~. , с., ..", . ,•.


\~ ~ ",
iilQ ~
\i! §!) R.~=
. "----_ _ __

Рис. 2.14. npOcMorp компонаl:lOЧНЫ)( блоков в


окне АээвтЫу Soout

Цравал панелъ. утилиты ПОЗВQЛ"Яет увидеть содержимое элемента, вцбранвого


в левой панели. При зтом можно увидеn. не толыю основные харwcreР.ИСТJI}tИ эле­
мента. ИСПОJJЪjyЯ ДJlЯ эror.о ВкладкуIl1fo (Информация), но И СООТВ~ТСтвующий. про­
грaммI1ЫЙ .код CIL. МоЖilо также coxpaIOIТb оиределецие элеме~та в файле XМL.

ИнструмеНТbI прое' ктирования Windows Forms


Windows Fonns являетсSI средством создания приложеНИЙ. воам.ожнoc-rи. 1ЮТОро­
ТО ' МЫ рассмотРим IWзже. А сейчас, чтобы продолжить рассмотрение SbarpDevelop,
щemrnw.rе на ярлъrnе ВКЛад1СИ Design внизу OlОШ програм:м:ного К.Ода M<a.inFor:m:. С .5.
Откроетс-н интеГрИрОБaI-lciое ою-ю проеJtТйрованил Windows RJпn:>.
С ПОМ(1)Щью элементов из раздела Windows Forms в ОlЩе Tooll> МОЖНО построить
графический интерфейс (GUI) для создаваемой фарм:ы. Ддл прuмера помеСТ~Те
один элемент типа Bl.ittOIi '(кнопка) в свою главную форму. сначала "Выбрав ПИК"
тограмму BlJtton. а затем щеЛRНУВ в окне проектuрощuщя. Для. изменения ~1Ща
любоro элемента МОжноиспалъзовать О1сно Properties (Свойства}. которое ЗRТIЩИ­
аяруe-rся с помоЩЬЮ выбора VieWQli'roperties из меню (рщ:;. 2.15). Выберите Button
из раскрывающеГося СПИСRa этого ОRНЭ. И уважите .цужные параметры ддя свойств
wtoro типа (иanpимер. ВасkСоiож: или Text).
98 Часть 1. Общие сведения о языке С# и платформе . NEТ

l.uttOnl System.windows J'onnsJ!utmn

~ i ЩI~ ~ 1ii\i
~~-----

Default
F.....
Тор. L.ft
. I . . . r.... Red
'. Backgrnundlmag. D (П""")
. Clu.esv.Hd<!tiorI TГU!!

. , С оntextМ.nо (попе)

Cursor Default

111. bкkground coIor us~ 10 dlsp\.., tat ..,d grophia


i. the tопtrоl. .

Рис. 2.15. Окно свойств

в этом же окне можно указать параметры обработки событий соответстJJYЮщего


элемента графического интерфейса. Для этого сначала щелкните на IIИR'I'Oграмме
с ИЗображением молнии (вверху окна свойств). а затем выберите из раскрывающе­
гося списка графический элемент. с которым вы хотите работать (В данном случае
это Button). Наконец. задайте правила обработки события Click (щелчок). напеча­
тав имя метода. который должен вызываться при каждом щелчке пользователя на
данной кнопке (рис. 2.16).
-
Prop"rt"" ®
buttoal System.Wi ndows.forms.Button '\i;
iТit} II l,i j i©1--------~ . ..
- ~-(f#:'

Ocaws wt. ... the mntrollS ditk~.

Рис. 2.16. Установкв правил обработки


событий в окне свойств

После нажатия клавиши <Enter> ShaгpDevelop сгенерирует npограммный код


заглушки для вашего нового метода. Для данного примера добавьте в npограмму
обработки события следующий программный код .

void ButtonClicke d( obje c t s ende r, Sys tem.Eve ntArgs е)


{
11 Поместим в загО1.l0ВОII: фориы новое сообщение .
t his. Text = " Пре кратите щелкать на мо ей :кн оп ке!";
r
Глава 2. ТеХi'lQЩJГИЯ ~е:Зl1.а~ll!~ JфlllЩjжемий на языке С# 99
теперь мО'жна запустить прОТр~ l:!a ВЫПОJШеаие (;вьфр<ill Debug~ Run из
меню). ЯСНО'. ЧТО В дщпюм С'ЛуЧэ.е при щеJ1'nte на КfЮПКе М;Ы ДОЛЖНЫ увидеть из­
меНИвшийси заголовок О'ЮШ формы.
Сейчас :8bl: ДО'ЛЖНЫ об.nадать достаТО'ЧНОЙ и:нформацией дlJЯ ТОТО. чтобы начать
:ИСПOJIьзование шпегрйроваююй среды рааработщr ~harpDevelop. Я надеюсь. чТО'
вы с'Моrли предСтавить себе ее основные ВО3МО'ЩДОСТИ, хотя, очевидно. ЭТОт ИН­
струмент может предложить ГQР.аэдо больще. чем была пoЩiвэноздесь.

Компоновка .NЕТ-приложениЙ с
ПОМОЩЬЮ Visual С# 2005 Express
Летом 2004 ТOДfl Мioro:soft предлО'жила . сов,ерше.вно новую серию ID&'ПРQДУКТОВ.
обоэначeюr,yю сдовом uExpress" (,СМ. bt tp: //msdn. microso,f t . сот! eXpres ~). На се­
ГOДJЩ вьщущено шесть пa1tе1'ов Э'rOГО семейства.

• 'Vuщаl WеЬ Developer 2005 ExjJress. ~ОблегчеШll:lIЙ'" вариант средств разра­


боТ>ки динаj\ПIчес;,ких Web-УЗ'lОВ и Web-се:рвисов XМL, ИСПО;JIЬзующих АЗР.
NEТ2.0.

• Visual Basic 2005 EJt1press. И~струмент~ ЦР9ГРаммирован:ия.. идеалыrые Al1Jl


программистов ·fiез большого опыта. 150торые хотят научиться строить .NE1'-
npmюжения с помощью дружесТВt;JU:{Оro СInl'Гakеиса V;i$Ual Basic .NEТ.

• ViSua[ С# 2005 Елргеss. V'Lsual Сн 2005 Express u vt...'>Ш11.,)# 2005 Express.


Специальные ИНС1'рументы разработки для УЧ~Я и ;шту~иаСТdв. npeAlIO-
'ЧИ'l:aIOЩИX ИЗуЧать OCHO~Ы' Иiiформатш<И в рампах I;:ИНт::щсиса соответствую­
щеro языка.

• SQL Вегиег 2'()05 E'xpress. СистеМа ynравленИfl базами ДEUlНЫХ нач:адьного


уРо1ilfШ. nреДПазнач:енная. для люБИ'rелеЙ. энтузиастов и учаЩJЦ:ся·р~работ­
'ЧИltов.

За~ечанм~. Во время подготовки ,ЭТОЙ tcМИГ:1-1 к печати семейство продуктов Expгess I! В\tIдe бета­
верСИЙ npeдnага:пось соверще!1I'!О б!аСnлатно_

По большому счeryr ПР.Qду1~ТЫ серий E1qJres& явлтотся "редуцировав:н~и' ие,р­


оиям:и их aIifJЛОl'ОВ из· VjЭI1а1 SbidIo 2005 1:1 ПР6дназначены rл.авН1:JМ образl))М ДJЩ
трбителей .NEТ и учащихся., кан и в .shazpDeve]bp. в Viзuаl С# 20015 Expre$s npeд­
лaraют~ IЩ:3J;пrnные средства. просъютра. оъ"Но проеюнрования Windows FoIП1S,
дJflЩоговое O~HO Адд References (Добавление ССЫ:IIОК). возможности IпtеШSeпsе и
шаблоны распmрения прnгpаммноro Кода. KptJМe того. в Visuш С# 2005 Ех"Ргеs-s
пр~nагает(щ несколько (очень важных) возМО'жпостеЙ. в настоящее время в
SlщrpD~Jор НfЩЭС1J1IIНЫX. а именно:

• интегрированный граф~есюа:й О17ЩЦЧИК:

• средства уцрощеюm доступа ~ Web-сеfЩЩ'~ XМL.

Ввиду того. что по 'вИДУ И пр~ испольвовшшв Vislla] С# 2005 Express


ОЧ~НЬ ПОХGЖ па VisuaI Stud10 2005 .(~ в I-IeНОТDрей сreпени на Sha.rpDevelop). здесь
обсуждеНйе указанно:й среды разработЩi не npедл.агаетсВ. Если вы ХО<J'ИТe узнать
100 Часть 1. Общие сведения о языке С# и платформе .NET

об зтом продукте больше, прочитайте мою статыо ')\n Introduction to Programm:ing


Us1ng Мicrosoft Visual С# 2005 Express Edition" (Введение в программирование с по­
мощью Мicrosoft Visual С# 2005 Ехргевв Edition), доступную на страницах http: //
msdn.microsoft.com.

Компоновка.NЕТ-приложениЙ
с помощью Visual Studio 2005
Если вы являетесь профессиональным разработчиком проrpаммного обеспече­
ния .NEт, очень велин:а вероятность того, что ваш работодатель согласится купить
для вас лучшую интегрированную систему разработки от Мicrosoft - Visual Studio
2005 (http://msdn.microsoft . com/vstudio). Этот инструмент по своим возмож­
ностям существенно превосходит все другие IDE, рассмотренные в зтой главе.
Конечно же. зто отражается и на его цене. которая зависит от приобретаемой вами
версии Visual Studio 2005. Нетрудно догадаться, что каждая версия предлагает
свой уникальный набор ВОЗМОЖНостей.
В дадьн:еЙIJIем при изложении материала книг," будет предполагатьCJI. что вы
предпочли использовать в качестве среды разработки Visual Studio 2005. С другой
стороны. и вы должны зто понимать. "по обладание копией Visual Studio 2005 для
изучения материала книги не является обязameльным. Самой большой проблемой
из тех. с IЮТОрЫМИ вы можете столкнуться в таком случае. зто обсуждение опций,
которых нет в вашей среде разработки. Но программный код всех примеров дан­
ной книги должен компилироваться с помощью любого выбранного вами инстру­
мента разработки.

Замечание. Загрузив исходный код примеров этой книги из раздела Downloads (загрузка) Web-
узла Apress (http://www . apress. сот), вы сможете открывать программный код приме­
ров в Visual Studio 2005 с помощью двойного щелчка на соответствующем файле *. sln. ЕСJ1И
вы ке ИСПОJ1ьзуете Visual Studio 2005, вам придется ВРУLIНУЮ настроить свою средУ разработки
так, чтобы вы могли ВЫполНить компиляцию соответствующих файлов *.cs.

Возможности Visual Studio 2005


Как и следует ожидать. Visual Studio 2005 содержит все необходимые средства
проектирования. средства доступа к базам данн:ых, утилиты обзора проектов и
объектов. а также интегрированную систему справки. Но, в отличие от средств
разработки. которые были рассмотрены выше, Visual Studio 2005 предлагает мно­
го дополнительных возможностей. Вот список некоторых из них.

• Средства визуального проектирования/редактирования XМL

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


смартфонов и КПК)

• Поддержка разработки программ для Мiсrоsоft Office


• Возможность записи изменений исходного документа и просмотра таких из­
менений

• Ин:тегрированная поддержка факторизации программного кода


)
Гiщ~э 2. rехнедОГИАСОЭДВНЙЯ nРИ11ОJК~НИЙ Аа А9ыке С# 101
• ){МL"библиотека раcmи.рeRИЙ nPОГРaммlЮГQ кода
• Визуальиые средства ЦОС'IJЮ.еИии КJ1accOB и }'-ТИЛЙТЫ теСТИрtii:QQЩrn объектов

• Окно определений nPQ1"paмм.EJ@TQ ~oдa. JЮторое rrpeдJIameТСЯ вмес.то утилиты;


Windows' Fbrmз 01а58' Vlewe:r; wiЪJ,c'7. ехе. npедлагавшейся в .NEТ версии 1.1 и
более ранних в.ерсий

Чеетно говоря. Visua1 8tud1o ~005 дредлarает так много воэмщкностеЙ. "<JТO д.лв.
их nOJ!Нoro оnисЩlИЯ требуется ~делънlШ книга (по объему больше ЭТОЙ). Наша
кнша решает другие~ада~rn. Тем fie менее, .в счел целесообразltЫМ потраТИ'lЪ не­
CKOJThК() стрaI:ЦЩ на OIЩсание !:'ШЦill[ 'ГлавНых усовершенс.т:воВЗНИЙ. IIpeдпожеШU>lX
в Vlsual Зtudiо 2005. По мере ''fТ('}ЩЯ материала книги вы будете подучать допоmш­
тeльнyI<) инФормщtmo О воз~ожв:остяхэтой интегрированной среды разраБOТRИ,

Утилита обзора реwений


Если вЫ С.11едуете УК~aI'IИЮOf Э'FОЙ главы, ТО создайте новое КOНCOJIЬHOe npилQ.­
жевие С# '(С' И:l\iеВeu Vs2005ExaцlpJe), выбр~Fil~NеWQРrоjесt из меню. УТИЛИ1'а
Solution ЕхрТогег (Утилита обзора решещm). дocryпна.п из мemo View. ПОВВOJIЯет про­
сматрШlа'tъ ююжество файлов и: ItОЩЮНОВОЧRЫX БЛОltОВ. ИЗ которых соогавленте.­
кyIЦИЙ npoeЮ' (рис_ 2.17).

,. 'гI
s Щ'~_
~. ~~Infi""s
~ ..» I\.~tnce
''!iIБ~~
-Q ~I!!m . o..~
.~ SffiI"I\.XmI
'ii\\lP~_.a

Рис. 2.11. Окно оБЗОРEl реШStIий

Обратите внимание на то, что пaпka References (Ссылки) в окне Sol'ution Explbrer
отображает СПИСОК цомц:оновоч;ны:х блохов, :на .коТ{)рЫ:е вы ссылаетес~ 11 В"асто­
ящий момент (KOНCOJ1ЪBыe npoeJ;rТБI по· умолчанию ССbIlIaIO'ГСЯ на S yst elТ1.. ct 1 ~ .
System.Dat-.а.dl1 и sуs·tещ •.XLml.dl1). Если нужно сослаться на другие компоно­
воЧНЫе БДoIOl. ЩeлRЮ1Тe правой JЦЮIIRОЙ МЬШJина IUl.П1<е ~eferences и выберите из
КOнтeI(C'tНoгO MeJ:llQ Add Reference (ДобавINъ ссылку). В появившем:ся диалоговом
ОШlе вы сможете вътбратъ вyжньtй вам :к<1МIIОНОООЧНЫЙ блок

ЗаМ.чан"." В VlsualStudlo 2пО5 noзволяеroя y~ывaтb ССЫПКИ на выполfllfемblе ((ОМПО~О80'ЖЫ8


блоки (В отличие от ViSLJal Studio .NЕТ2.00З, rде IiAaHHOM KOl'lreK~e можно было и.сrrOJiЬЗО88lЪ
только бибm.,оТ8' КИ программного фда ..... dll,).

}Iаконец. обратите внимание JIa ШIктоrрамм:у Properti'es (СвоЙс.тва) в овне


Solution ЕJфlоrег.В реЗультате двоmюго ЩeJ"lЧJ(З. на ней поНВЩiется: окно раCIПИpeн-
1IЩ'0 p.eдaJ(.Topa хонфигурaцшt. ироекта (рж. 2.18).
102 Часть 1. Общие сведения о языке С# и платформе .NET

.---=:=-=.::=::;
-- - -·c~·- . - - -- ~_----
о -._,-.-'-----. "-- ---.---
- -~'-
'

,i дpp/ication
:-- ~ -- -'--- l

i~ l
, bld Events !,

Рис. 2.18. Окно редактирования свойств проекта

Возможности изменения naраметров проекта в OIше PrOject Properties (Свойства


проекта) будут обсуждаться в книге по мере необходимости. Но даже при беглом
его изучении становится ясно, что в нем можно установить параметры безопас­
ности, изменить имя компоновочного блока. указать ресурсы командной строки и
задать конфигурацию учета событий компиляции.

Утилита обзора классов


Следующим инструментом, который мы собираемся рассмотреть. является ути­
лита Class View (утилита обзора классов), и ее тоже можно загрузить из меню View.
как и в случае ShaгpDevelop. эта утилита обеспечивает возможность обзора всех
типов. входящих в текущий проект, с объектно-ориентированной точки зрения.
Верхняя па:нель соответствующего окна отображает множество пространств имен
и их типов, а нижняя панель представляет члены выбранного в настояш;ий момент
типа (рис . 2.19).

,jJ Q Project Refer_nces


S () ",2005Ех"",*
5 т Prog-....
,jij Q 6аое Турео

Рис. 2.19. Окно обзора классов


[
Глава .2. lехмологиSl СОЭД~НИI1 лри.riожеыиЙ На ЮI:же CJ 103

.окно определений п· рограммног() кода


Если ВЫ имеете опыт лрограммированин В .NE'Т 1.]. то должны знать об .)"ТИЛИ-
1'€ Windows Fbnns Class View~r,~incv. ехе
(уrШlИl'а Qб:юра клаССОJJ WшdОW$ Fbлns).
этот Иifструыент ПQЗВQJщет задать ИJ\m .NEТ-тпna и цросмртрет!> его С#-определе­
НИе. В верСЮi ..NEТ 2,0 УГШЩТbl wi otJv. ехе уже Нет. но зато есть усоверШенство­
ванная версия этогр средств:а. интегрировammя В V1sщll С, 2005 ЕхртеSБ и VisuaJ
Sttldio 2005. СОQтветствущщее ОЮlО Code DEtfinition (Оюю Qпределе~ про.грамм­
ного K~дa) МОЖНО OTRpЫTp череЗ меню View. Пом~е курсор ~яа любой ИЗ
типов :в проrpaммно~ KOД~ С'#. и вы увидите определeIOlf: соот:веТC'ТВJ1Oщего тИnа.
Например. ес;щ 'lдeтmyT~ ~a 'tИов:е ~stлпg~ в рам}щ''{ метода Main () , будет похазано
опptделеf1не типа мО!.сса S.y;;;teIТI.Etring (рис. 2.20).

99 11!11ОР-:-"Р"се S.~"Ц
-. f \
-S 1> _,.p-UOl1. С 'Э'е~lе>d cl ~Zla 5:::::-.:.:JйЩ : ~ ~: ~·'М;f·~ J.--~ ,
:;,t ' ,..,...,- .,,~. .--, ,..'" ,-"
.: _, r~ ~~~'" St"i1!.V {Dn !>" · val"'!!';
" ,i!JJ: ~'~J':!." зtri:>q (cil.. з; [J v'а1 ЩtI I
'_>!t . .'~l. ~ " Scringt"b"x; .... yal "...}·,;
~. J, 1~,cl:;li~ sц.l.t1litы-~!:lz 1:, Lm: с6;,ш't.,) , ; '"
.~ ~~'~~r~~~~i.j~ ~c~ , .- -- - - -

Рис. 2,20. Окно Ol1ределений nporpaмMHOrn ~oдa

Утилита обзора объеJ<ТОВ


Вы дOЛЖНЬJ ПОМIШТЪ из r.лaвы 1, что В Visual StudiQ 2005 eCTI;o yтwmтa Д.IlR по­
смотра RОМnОIIOlЮЧНЫ)J. блоков, на ROторые ссылается UPOffitT; АкТИВI!!~ируйге оlUЮ
Object 8r{)wser с ПОМQЩЫOме.ню Viеwё>оtЬег Wihdows. а затем ВР1'беРИ'J"е компоНовоч­
ный блок. который вы ж~те из}"'.lить (рис. 2.21).

ИнтеГРИРО'В8нная поддержка.
фактор,изаци,и программного J(oAa
Одним из rлавных усовершенствовщпШ. лредлага~мЫ1f в VisuaJ stщ:Но 2005,
лвЛЯется встроенная поддержка фак'1'ОР:ИШЩИИ nporpaMMHoro кода. ГоворН уцро­
щенпо. фа.кториззnиs о>Значает форм;щьщ;тй -механический" арОЦССf;:УСGJвершен­
с'rnОВaюm существующего базового JЩЩI.. В прomпом процесс факторизации пред­
по.чагал orpoмные об:ъемъJ ручн()го труда. В Visaal StudJo 2005 значителънЩi часть
соответствующей работы ВbПIолняетсн автоматически. Используя меню Refactof
(Факторизация). tоотвеТСТВд'ющие крмбпнации клавИ!П . смарт-теги иjиди вы-
308М :контекстного меню !l: по)1"ощыо щелчков мы:ши . вы Moat eTe придат:ь своему

протраммном;у КОдУ совершенно новый БИД. затратив на это МИНИ~ уси:л:и'й.


в таб:IL2. 4 приведены н:еl,оторые общ»е в:оманцю факТdриэациn. расПО3ЮШаемые
в V15ual Studio 2005.
104 Часть 1. Общие сведения о языке С# It платформе .NET

~\т'~~'I~~~'
<Seiord1>

Рис. 2.21. Утилита обзора объектов в Visual Studio 2005

Таблица 2.4. Факторюация в Visual Studio 2005


Метод факторизации Описание

Extract Method Позволяет определить новый метод на основе выделен­


(выделение метода) ных операторов программного кода

Encapsulate Field Превращает открытое поле в при ватное, инкапсулиро­


(инкапсуляция поля) ванное в свойство С#

Extract Interface Определяет новый интерфейсный тип на основе множе­


(выделение интерфейса) ства существующих членов типа

Reorder Parameters Обеспечивает изменение порядка следования аргумен­


(перестановка параметров) тов

Remove Parameters Удаляет данный аргумент из списка параметров


(удаJ1ение параметров)

Аепаmе Позволяет переименовать лексему программного кода


(переименование ) (метод, поле , локальную переменную и т.д.)

Promote Local VariabIe to Parameter Перемещает локальную переменную в набор параметров


(перемещение локальной пвременной определяемого метода

в параметр)

Чтобы проиллюстриронатъ возможности npименения средств факторизации на


практике. добавьте в метод Main () следующий прогрaммный код.

static void Main(string[] args)


{
// Определение хоисолъиоrо иишерфейса (CUI)
Console.Title = "Мое приложение";
Console.ForegroundColor = ConsoleColor.Yellow;
Console.BackgroundColor = ConsoleColor.Blue;
f"nasa 2, Технаnoгия созцаНI4Я ПРИ'ложений на Я3Ыkе С# 105
Cori'soJe . Wr i t-eLirl~ ( .. ** ......... ". *'** * ..... * ....... "' ..... 1< ... " ....' ~ ........... ..-., .... ** ." . . "" ) ;
СФnsоlе.WritЕ;Li'nе("*·"**~?i*" Э'])О ·}.юе nриложе.нИе! *",оН"''''''''};
COnS.o le. W,riteLins (....... ". **,о ."..... " .... * .... ~ ........ * *,... * **'* ... ,.... * -k-k* * .. ") ;
con'S-01е. Ба сkgrочndСоlОЕ = C.onsoleColor. Glac-k;
/I о.и~ilиие ВахiJ.'X!PlЯ JC.llliIВJOIIИ Дт'I завериtelWJl ра.бо!rW.
COn.sole. Reac:Ц.,ihe ( ) ;

Этот np~Грaммньrй IЩЦ .вполНе рабo'tоспособен, но представъre себе. ч:ro B~ хр,­


тите QтобраЖать генерируемую им подсказку в разных :мес.тах вашей программы .
Вместо того' чтобы ВВОДИТЬ вручную операторы ()пределeIЩЯ интерфейсС1, СНОВа
~, сНова, бьmо бы цдеan:ьио иметь помощника. ltO'Торый МФГ бы делать э:гоза вас.
~ счастью. в данном случае вы може'I'е npимеJIЙТ1>
JC с,-уществующему прОГрWdМНО·
му КОДУ :метод фaRтО}ШЗЗЦИИ Extr~ct Меttюd (Вьщмение метода). Сначала в онне ре­
даитора выберите все операторы nрffi"paмIOЮГО кода (за иc:wnoч~ни.ем: последнего
вызовасо:ns'ыle .ReadLirie (», Затем щелкните npaвoii taIОIПЮЙ мыши И из ПOЮlИВ~
шегося новте.кс'ГНого меню Refactor выберите оIЩЮO
Extract Methpd. в nOЯВИ;ВШ~М­
си диалоrовом окне унажите ими нового метода - Conf igureCUI (). Б реэу.лщат~
вът обн:аружите, "Л'О' теперь метод Main(} вызывает новый VI'CFJeРИРОВa:ню.rjii метQД
Соп!:' iч,urеСUl ( ). содержащий ранее выделеннъtй про.rpaмr.щый код.

сlааз Е'з::оgram
[
~;'tatic void Z,Ia:l:n (stringI ] args')
I
Conf.i.gureClJI () ;
j J Ожидание наж.аТИJiJ 1ШавИЩИ для '3.аll~рще!iИЯ работ~.
C;onsole. ReadliIle () ;
}

private atati с void СОnf:tgti1;еСЩ ()


l
IJ оupe~е.певие ~OHCO'-.O%'O ИII'1'еptеЙса (CUI)
C0l1s.01e. Ti tle "" "~e nРИд'ожеtiи-е'" "
CO!'Jsole. ForegroundColor = CQ.lliJolecolo·r , 'iellow;
СОnЭоlе .. БасkgrоundСоlоr "" COlls'oleColor . .Blue;
'.CoX'lso1e .. Wr:i teLi,ne ("'" *" ~ *..... * * ",..... * * .........** .. r.*" '"*" ** .... '* .., .* * "*"") ;
СОnЭQlе ,.W.r·.ite.ЬiDе('''** .... * " ... '* Это мое ПРИЛ.ожение! ..... ,j,*** ...... );
c'onsole .. WriteLine с"" ***,;, "** *- *т"" . ,." * "",*"" * " ... ~ . .... " *" ... "-"*'1) ;
'qon:;o le .• Bac~groun dColoiL ~ CGf1S01eCelo.I. !Uack;

'Замечание. Если вЫ хотите Зf1аrь бо:nьше


() процессе факторизации и ее псщдержке в Visua1
Stщtiо 2(105, лрочитайте мою статЬю "Refactoгing С# Code Uslng VlsualStudl'o 2005'"
(Фа~торизаЦIilIf rt:рограммнагф КОД;! С# в Vlsual Stщ:ljо 200.5), дротуnн)'ю на стран.\1Цах
hHp: //mscm • micr050ft . cdПL
106 Часть 1. Qбщие сведения о языке С# и платформе .NET

Фрагменты программного кода и окружения


в Visual Studio 2005 (как и в Visua1 С# 2005 Express] предлагаются разнообраз­
ные возможности автоматического добавления сложных блоков программного кода
С# с помощью выбора вариантов меню, контекстно-зависимых щелчков кнопкой
мыши и/или комбинаций клавиш. Число доступных расширений протраммного
кода весьма впечатляюще и может быть разбито на две главные группы.

• Фрагменты програм.много кода. Это шаблоны блоков программнаго кода,


вставляемые в том месте, где размещается курсор мыши.

• Окружения. Это шаблоны окружений, в которые помещаются выделенные


блоки операторов в рамках соответствующего контекста.

Чтобы воспользоваться соответствующими фУНlщиональными возможностями,


щелкните правой кнопкой мыши на пустой строке в пределах метода Main () и ак­
тивизируйте меню lnsert Snippet (Вставка фрагмента). Выбрав соответствующий
пункт меню, вы увидите, что указанный программный код будет добавлен автома­
тически (нажмите клавишу <Езс>. чтобы СI<РЫТЬ всплывающее меню).
Если вместо этоГо щелкнуть правой кнопкой мыши и выбрать пункт меню
Surround With (Окружить с помощью ... ], вы увидите другой подобный список опций.
Найдите время и без спешки исследУЙте встроенные шаблоны расширений про­
граммнаго кода. так как с их помощью можно значительно ускорить процесс раз­

работки программ.

Замечание. Все шаблоны расширений программного кода представляют собой XMl-описа­


ния программного кода, генерируемые средствами IDE. В Visual Studio 2005 (и в Visual С#
2005 Ехргезз) вы можете создавать свои собственные шаблоны. Подробности этого про­
цесса описаны в моей статье "Investigating Code Snippet Technology" (Исследование тех­
нологии применения фрагментов программного кода), которую можно найти на страницах
http://msdn.microsoft.com.

Средства визуального проектирования классов


в Visual Studio 2005 есть возможность конструировать классы визуально
(В Visua1 С# 2005 Ехргевз такой возможности нет). Утилита Class Designer позволя­
ет просматривать и изменять взаимосвязи типов (классов. интерфейсов, структур.
перечней и делегатов). включенных в проект. С помощью зтого инструмента можно
визуально добавлять., модифицировать и удалять члены типов. а результаты мо­
дификации будут отображаться в соответствующем с#-файле. Аналогично, если
изменить данный с#-файл. соответствующие изменения будут отражены в окне
диаграммы классов.

для работы с этими возможностями VisuaJ Studio 2005 сначала нужно создать
новый файл диаграммы классов. Это можно сделать по-разному. и один из вариан­
тов - щелчок на КНOIше
View Class Diagram (Просмотр диаграммы классов). которая
размещается вверху справа в окне Solution Explorer (рис. 2.22).
После этого вы увидите пиктограммы классов, входящих в ваш проект.
Щелчок на изображении стрелки будет по:казываьь или скрьшать члены ТШIа (см.
рис. 2.23).
r
Глава 2. Т~ХНОJ10ТИЯ с:озцаН~1Я f1l11lWоже.н I1 И ttа. RЗЫкг С#· 107

a~
':i.1 ~l!\fD.",
ii1 !Q Referen=
, .:1 .$!NI!1
·0 Sy_ .'!II>ta
.Q 5~K'"

Рис. 2.22. СQэда~е ФI!J'iIlа диаграммы классов

Рис. 2.23. Просмотр диаrpаммы клаО(;/i)В

Э1уynшиту удобноиспольэо~ать с двумя другими :воэ,мОЖНОСТЯМИVisuа1 Studio


2005- окном Сlз.Ss Details (ахтивизируетс.я из Merцo ViewQOtherWindoWS) и .p~дe­
лом Class Deslgneг панели инструм:ентов (ав.ти:вющруется из :меню V·iew~Toolbo)().
ОIO.l.о Class Details не roлыю щща.зъmает струк.туру выбранного в наСТOЯIiJ;ИЙ момент
элемента дцагрэммы. 80 и поавол.лет .МРДИфИЦЩJооа'rЬ СуЩествующие и вставлять
новЫе ч:дeньt ~aeca (рис.2.24).

-.• .• ., .... , - ~ .. " ' . ~I ••

e l"l~

'" JjfIПIIII уо1с!


I.Т\II SIrn!!IfJ

Рис. 2.24. Окно содержимоrо КЛаССОВ

Паве;:IД I:IHCTpyмeHTQB [рис. 2.25) поэ:волне:г с ПОМОlЦью визуальНЫХ средств


щ:-rавлятъ в проект НQI"ы~ ТИПЫ из раздела Class Oesigner {и создавать связи МеЖДУ
этими 'типами). (чтобы э'r!)т раздел панели :инструментоt! был ВИДИМЫМ. ОННО диа­
граммы КJIЗ;ССОВ дол:.ащо бi!1ТЬ юстивНbl.М_) При ЭТОМ ЮЕ автоматически создает но­
вые' Qnpeделения Q#-ти;пов в фоновом режиме.
ДтJ. пр~ера щ~ре';l'q:щ~ новый нл:асс из раздела GlaS9 Designer панет! ШIСТРУ­
Me~ron в окно диаг~ КТiaCCOB. В соответствующем диалOl'овом окне укажите
Д1lН Э!I'OГО HOBorO щщ~са m.w Car (а:втомоБНЛЪ). Затем. используя оюro CfaS$ Details.
добавьте в.класс рт:крытое СТРОRШlOе Dол.е. на.'П1ачив , ему .иМя petNa.1.tI€ (имя ;noбим­
да), каж показано !'Ia рис. 2.26.
108 Часть 1. Общие сведения о языке С# и платформе .NET

о Delegall!
4-lnheritoInce
*'- A~1iO(1

tAc~

Рис. 2.25. Вставка нового класса с помощью визуальных средств Class Designeг

Рис. 2.26. Добавление поля в окно содержимого класса

Если теперь взглянуть на определение С#-класса Car. вы увидите. что оно соот­
ветствующим образом обновлено.

public class Car


{
/1 Испоnъзо.а~ъ o~xp~e данные без необходииос~
/1 не рехонеидуе~ся:, но здесъ з~о сде.пано дnя: npoc~olJ!lol.
public string petName:

Добавьте в Ш,НО диаграммы I\Лассов еще один новый класс с именем SроrtэСаr
(спортивный автомобиль). Затем в разделе Class Designeг панели инструментов
выберите пункт Inheritance (Наследование) и щелкните на пиктограмме Iтасса
SportsCar. Не отпуская левую кнопку мыши, переместите указатель на пикто­
грамму класса Car. Если все было сделано правильно. вы должны получить класс
SportsCar. являющийся npоизводным класса Car [рис. 2.27).
Чтобы закончить построение примера. добавьте в сгенерированный класс
SportsCar открытый метод PrintPetNarne ().
public class SportsCar : Car
(
public void PrintPetName()
(
petName = "Фредди";
Сопsоlе,WritеLiпе("Имя этой машины: {QJ", petName);
}
ГЛ8'ва 2. Технология с{),зtJ,аНИI1 ПРИЛDжений на язше 0'# 109

GiI Meltiolf~
ti.(# М.fп

": " tsalr' I?]


"'Cw·
[
............... ~

РIЮ. 2.27. В~Эо/a!I1hНое ПСJЛУЧ!'!f1ие llРОИ380ДНrJГО клас!!:\} из класса, имеющеrnСFl в 'наличии

Стенд теСТИРОlвания объектов ' (ОТВ-тестер)


Еще ' одним удобным инструМентом Бизуэль}Iый рawаб()'J'IЩ р Visuai Sfudio 2005
)'jВ.i1Яетея ОТВ-тестер (Object Thst Bench - стеНД, Te.C'I1'1pOIlaDRfi абъеюuн}. ЭТОТ ин­
струмент ШЕ noзвалнет быстро соэдать экземцлнр ющеса и ВЩIЮЛНИТЪВЫЗОВ его
членов без КОМIIИЛЯЦИИ:и вьnroЛ1t~нии вСero ПРWIоже~$I. Эте очень удобltО в тех
СЛ:У-Ч<l:ЯX. J<OFД8. вы хотите проверить работу KOEtкpeтI'IOrO М{:ТQда" но в обычных
усл'ОЮ1RX дЩI этоrо требуется "пройти" через .дeиrrJ(И стрОК IJРОГp3ММI:ШI'О кода.
Дли рабоТБ! с ОТВ-'l'естером щеЛЮIите правой JffiОrшpй j'dЫlIIИ на типе. кото­
рый ВJ:d <:o~дaeTe с ЕО:м.ощь.ю 01rn.a nPОeRТИР0Ванюl. хлзссов. Например, щeJIКни-re
uращш К.Е!!mКой МЪПlIИ на типе Spor,t sCar и:из по.явившегочя кoнтexcТllOro ме:ию
выб~рите Create InstалсеQSрогtsСагО. По.\Ши'ГС'Н диалоТщюе ОJШd. которое позволит
зада'IЪ:ИМЯ вашей временной оБЪентной переменнОil (и , ecJ,IИ нужно. предоставить
ROнс,труктору н:еобхоДимые аргументы). После заверmеmm :цроцесса ВЪJ обнаружи­
те С:Щ)Й Qбъект в рамках IDЕ.ЩеЛl(1Щте право~ инощщlt МЪШIИ на шштограмме
об1>екта и вызовите Метод PrihtPetName ()(рис. 2.28).
ВЬ! увщите соо.бщение ~Имя этой мannпIЬt: Фредди', J;юторое ПOflВИтся В ViSua1
s;tцd.iq 2005 в рамках ~toнсоли Quick.

Рис. 2.28. СтеНд теОТ1llровани.11 объеКТQВ' BVisual Stud,iQ 2005


11 О Часть 1. Общие сведения о языке С# и платформе .NEТ

Интегрированная справочная система


в завершение давайте обсудим возможность Visual Studio 2005, которая по
определению должна быть удобной. Речь здесь идет об интегрированной спра­
вочной системе. Документация .NEТ Framework 2.0 SDK исключительно хороша.
очень удобна для чтения и содержит очень много полезной информации. С учетом
огромного количества встроенных .NЕТ-типов (их число измеряется тысячами) вы
должны быть готовы закатать рукава. чтобы погрузиться в глубины предлагаемой
документации. Если же вы к этому не готовы. то при разработке .NET-приложеНИЙ
вы обречены на бесконечные трудности и многочисленныIe разочарования.
В Vlsual Studio 2005 предлагается окно Dynamic Help (Динамическая справка).
которое (динамическиl) изменяет свое содержимое в зависимости от того, какой
элемент (окно. меню. ключевое слово исходного кода и т.д.) является активным в
настоящий момент. Например. если вы поместите курсор мыши на класс Console.
одно Dynamic Help отобразит набор разделов справки. имеющих отноmение к типу
System.Console.
Тю<же следует знать об одном очень важном ПОДl\аталоге документации .NEТ
Framework 2.0 SDк. В разделе .NET Development~.NET Framework SDKqClass Ubrary
Reference документации вы найдете полныIe описания всех пространств имен из
библиотек базовых классов .NEТ (рис. 2.29).
каждый 4 узел М здесь определяет набор типов данного пространства имен, чле­
ны данного типа и параметры каждого члена. Более того, при просмотре страницы
помощи для данного типа сообщается имя компоновочного блока и пространства
имен, которые содержат рассматриваемый тип (соответствующая информация
размещается в верхней части страницы). Я предполагаю. что при изучении ма­
териала данной книги вы доберетесь до очень и очень глубоко спрятанных узлов,
чтобы получить важные дополнительные сведения о рассматриваемых объектах.

~by;

ft( D",'elopm."t ТooI. ond L.m_


ltt En~'ise s..-v .... and Development
(~ Мoы. апd Emtжjd~ D~/е/ОР"'епt
6: .NEТDeve~t
Ы_ ,tEТ Framework SDtC

~{ Deblt~)
'*' дcc..sibility
1):) IEНostEl<ecut..
r:tJ Мicrosoft . Дspпеt.Snapoп
i±I Мicrosoft. ВuoId .ВUIIdEngOne
(-11 Мicrоsoft.SUIId.Fт'ame'л-or<
liJ' Мlaosoft.~.Tasks
$ Мicrosoft.Вuid . Tasks . DepЮyment . ВОоl$tr. .
""', ......""",. .. .а..< Т. . . . , , - , " , _ " ' /oobrn..... ~'
~:.~~~~~~:~~:;'%:r:~:.:; ~ ~} ::'-,_ " A~
,U} ~~СОП,~,I$ !#~ Favorf~/

Рис. 2.29. Справка по библиотеке базовых классов . NEТ


r
!
j
1

Глав,а 2. fеХНQЛОГИЯ ооздани-я при/!{}жений rta языке С# 111

Дополнительные средства
р'азработки . NEТ •прило,жений
в зaиn:юqеНJfе' хотедосъ бы обратить ваше »нимание на ряд инструменто!3 раэ­
работхи .NE'f. которые MOry"I' ДОiЮlIlIИТЬ фунхционэ.ды1lыыe щ>Змqжнос:ги ныбрашюй
вами, ЮЕ. МllOrJ'!e из упQМЯНуТЫХ эдесь ияструментов ИМ!ЖIТ O'J'RрытыИ ИСХОДНЫЙ
код. и псе он:иffiесплат.щ.I. В этой Ю-Iиге нет места ДЛ;А подроб~ого onисания этих
yтиnИ't. яО в табл. 2.5 пji>едставлены ОIIИсанив mtCтрумеитов, которые я счятi110
чрезвычайно поле~, а тaIo!re URL-адРеса. до которым можно найти дополни­
тельную информацию.

r..бпи~а2.5. Подборка ОРМСТEl разработки .NЕГ-ЛРИJ1DжениЙ

Название Описание URL-аАрес

FxCGp Эшг инструмеlfГ ВХQДИТ а разряд оБЯ.ззтеЛ!>­ ht !.p~ / / www.g0tdotne!: .с от!


ных дпя любого разработч~ка .NЕТ-прможе­ team/fxcop
НИЙ, ЗIbIнrерщ;osаннаг.о ~ совершенствова­
нии СВОJ.1Xпрограмм, FxCop ПРОВElРИТ любой
КОМnОНI'JВО4НЫЙ блOIC .NEТ на сощtleТC"rnи.е
ОФИЦЖlЛl:!НЫМ требованиям и рекомендациям
MicrO$oft .NET
Lulz Roeder's Этот усosе/i>шеНСТВОВaRНЫЙ д~){емлИJ1ЯТОрI b t. tp: 1/ W'w w .,ai s"t6. coml
RefleC10r 6раузер оБЪeuОВ , NEТ П'ОЭВQляет пр.о~на­ t'D.eder/dGtnet
ДЛЯ .NE1 лизирGlFrJТЬ реализацИЮ тобаго .NEТ -"Типа,
ИСПОЛЬ3УlOщего CJL, С# . Object Рвэсаl , NEТ
(Delphi) ИЛI1 Visuэl Basio .NEf
NAnt NАпtявляется .NET-ЗКВИ,!ЩЛентом Ant - по< http :// s ou.rce f org.e .net f
nyiтяРНQГО автомаТИ3l:1роиаJ,iНОГО средства рrоjес t зlПarJt
'СDЗДВИШl модулей' Java. NAn1nоэволяет
определять и ВЫПОЛНЯТЬ tтOAlJOO!ibIe оценарии
,I(ОМПОНОВКI1 , используя {;интаксис, ХМL

,0000 О помощыQ NDoc можно reнeplilpoвaт, b фай­ h tt:. p: I !:s Qurc efarge:. <Ie't J
лы документации ДЛЯ программного кеда pr.ojее t-s /ndoc
С# (.или , компилИрованных f<,OMnOAOBO'l!fbIX
блоков .NEr) s самых пот1,улярныx форматах
( ". сЬт MSDN, XML" HТМL" Ja~do1: и LзТеХ)
NUnit NUni1 являеТСЯ.NЕТ ,..эхвиаалентом инстру­ httр,:/Jwww.ТIJ:щit.оrg
мент.а JUni1. преДНаЭНЗ"lещюго ДJ1Я l'eCTl<lpo-
НВЮ'lЯ Jwa-модулеЙ. С ПОМOt;'цЫ0 N1Jnlt можио
ynроО1'ИТЬ "рсщеtс лроверки управляеМQГО
Ilрогрвммного кода

Vil Восп~нимайте ViI Ka~ ·с;таршего брата" раз­ h:ttP:/{WW'W'.lbot. сот


рабоrчика .NЕТ.Этот ИАСТРУмент ПРОЗИaIm,м­
рует лрограммный КОД, .NEТ и предложит ,РЯД
рекомендацИй отно.ситеnьно того, как 'YllY'l-
ШиТЬ его о ПОМОЩЬЮ фаКТОРИЗЗLIИИ, с1"рУКТУ­
рированной обработки ИСКJ1ip!-lf!НИЙ и "Т.Д.
112 Часть 1. Общие сведения о языке С# и платформе .NET

Замечание. Функциональные возможности FxCop сейчас интегрированы в Visual Studio 2005.


Чтобы в этом убедиться, выполните двойной щелчок на пиктограмме Properties (Свойства) в
окне Solution Explorer и активизируйте вкладку Code Analysis (Анализ программного кода).

Резюме
Как видите, в ваше полное распоряжение предоставлено множество новых
игрушек! Целью этой главы было описание самых популярных средств создания
программ на языке С#. которые могут ускорить процесс разработки. Обсуждение
началось с описания того. как сгенерировать компоновочный блок .NEТ, не имея
ничего. кроме бесплатного КОМIIИЛЯтора С# и программы Блокнот. Затем мы рас­
смотрели приложение ThxtPad и выяснили, как настроить этот инструмент на ре­
дактирование и компиляцию файлов * .св с npогрaммнblМ кодом.
Были также рассмотрены три интегрированные среды разработки с более ши­
рокими возможностями: сначала SharpDevelop с открытым исходным кодом , затем
V1sual С# 2005 Express и, НaIюнец. Visual Stud10 2005 от Мicrosoft. Эта глава толь­
ко коснулась всего богатства функциональных воэможностей каждого из этих ин­
струментов, чтобы вы могли приступить к самостоятельному изучению выбранной
вами среды разработки. В завершение бьш рассмотрен ряд инструментов разра­
ботки .NEТ с открытым исходным IЮДОМ, которые могут преД1IOЖИТЬ разработчику
дополнительные возможности.
ЧАСТЬ 11
языIK
программирования С#

в этой части .••


Глава З . ОСНОВЫ языка С#
Глава 4. ЯЗ,ык С# 2.0 И объектно-ориентированный' ПQДХОД
Глаl:1а5. ЦИЮl суЩествования объеlCFОВ

Глава 6. СТруктурироваfilная обработка исключений

Гпава 7. иl'fтерфейсы и коллекции

Глава 8. Интерфейоы обратного вызова, делегаты И' события

Глава 9. Специальные приемы построения типов


Гnава 1'0. Обобщения
ГЛАВА 3
основыI Я3ЬIка С#

В оспри.r:iIJМaЙТе 3rLY r.паву вак КOJtЛeJЩJUO тем. по:свmценных ОСНО:вщ,IМ вопро­


сам J;Ip~нeшtя Jlзыкc't С# и йсполъэовa1'lИЯ n.тщтфQРмы.NЕ'I~ в Q'ПЛИЧИеQТ
CJIeдyIQЩИХ глав, зцесь нет одной Ве,цу'Щеi'1 'ТеМЫ, а npе.длаг'dЮТСЯ WШIOСТрации це­
лого рида узких тем. 1<Оторые вы должны освоИ'.тъ. Это. п чщ:тности, ТИIII:iJ данных.
характеризуемые зНаЧеНИЯМИ. и ССЫЛочные JiШЫ ДЗlЩhIX, RОНСТРУКЩИИ УСЛQВНOI'd
ВhlQО~:Щ Ц ЦИ;JUIа, механизмы лриведении R объеК'1'НОМУ ТИ11У и 130сетащтJreНИЯ из
~объеК'ГНог() образа~.· POJIЪ Syste-m.ОЬjесt и 0030ВМТехдИ,~а' поетроеЮ1-Я .классов.
По ~oдy Д~ вы тав:жеузнаете. кав в рамках СИНfl'aRсиса С# обрабатываютсЯ cтpo~
I~И. ма:GCИf:!J!d. перечви н структуры.
ЧтоfЩ ИЛЛIOс:трировать баЗО13bIe npииципы прщ.lенеНШl языка, ~ рассмотрим
биfuwо1i'CКИ бааовых юraс-Сов .NEТ и UOC'I'роим рл:ц. npим:еров ПРJЩожеНИЙ. ИCIЮJIЬ~
зуя рaщ:mчныетнn:ыз пространства И:М:ей SyS'tem. В зто;й главе также рассмаТри­
lЩет~ такая RO-ванвозможность яэыI<a С# 2005', КЗ1( тип данных с разрешением
ПРИЩJматъзнач.еШJе ou 11. Haкo~. вы узнаете. как .в С# с помощью ЮlЮ'Ч:евоrо
слрва nатезрасе объединить тЙlIЫ :в o1ДeJlЬНoe пространство имен.

Структура простой программы на С#


Язык С# требует. Ч1"обы ВсИ nоrmш ДРОГРаммы содержаласъ в рю.iКах определе­
нйя. нек0ТОрого ТШIа (эсдомнИ'rе JЩ rла,вы 1, ЧТО термин mun.:и.спользуется для Qбр­
энач-ени.я любоrо элемента: MR-tj,Жества {JCJI.CICC. J.JJ1Л"!РфеЙс. cmp1JJcmypa.. neречен.ь.
делеzam1). в o:I1JIИ1n1е ()!I' с(н). 13 С# не ПО:ПЮЛ.Щ.~"n:Я- создавать глобальные фующий' и
глобалыше элементы да:е:ных. В просте;йш~й своей форме прorpамма на С# может
быть записана J;J следующем виде.

11 по CO%'~"eJIJII:) Сt-фaйn:к ИIIeJOi'LI раCDiИp8ИИ8 * . С8.


l.lВir'9 3ys,t em;
cld.'S S HelloCla5,~

!
publ ic static in't Ma.:tn (эt.ring 11 args)
t
Console .. Wri teL;:ln-е ("Mello W.o :rld! П) ;
Cons·ole . ReadLine () ;
rеt\Jrл О;
116 Чвщ. 11. Яаык про.граммир.ОR;tf\l\it С#

~Cb oд.p~~~[ '.111Щ,:кцаСlJа /8<el1o,:la:ss). nодцерЖЮ\-аюЩliЙ f}дmIСПlешIВIЙ


.м'eTQД. Щ>ТОРQiИf в:аЗl::l'а'i.ево имя Ма j.!1. ( ) • Каждо~ В'ы.ло.лниемое С#-.приложе.яие
40Щl(Нl:) ' сщreржа'l'Ь марс, оцредм.шощий :метод мaitj\.), ROторый 11It:1"10ЛЪЭуетс.я Дl1)I
rOбomщчe:I:I}Щ 'ТОЧRИ B~дa.I;I~ !\.ах .mЩИ'r~. здесь с мeтDДQM MaifJO св.яз,а­
JlЫ К;?JЮчeвъ,rе с-,,'Юва publi€ и st.a.ti.c, Пelаже БY.цyr ПРe,ll;ставлеiIЫ их форма.льRЬre
QдредеnefDiЯ. а ЩOJ:Ш Чt~0 вам достаточно:шmъ. что onqJblTble членЫ (рubliф) .fIP-
С'хуцны д:!ш ДРУГИХТШЮВ', а СТa'ГI!Чеcюre ЧJreНЫ(:sUtic J раосматриваютсJ'l на уров­
не юr.aеса (11 Ji'eJiВ,. ~не0'бъеE't"a) и ПQЭ'tl~ могут &JЗЫИaТЪСЯ: без еоа,цa:RИЯ 80001'0
экзeмn.qщ>а rщцеса.

3амечание. ЯЗ/)lk Ц#: ЯВJтяеТQЯ Я3ЫIC'О~, '1увотвитеft1;НЕоIМ к реп-ф;гру O\'fМBQJ:IOB, j.i,aпримерс, Маln
З\D,есь отл.имаетСА, от l'I1airL, а Readliue - от ~еаa:L_ihе> П~ЭТОМУ ~i1~yeT ПQД4~J)1(НУГЬ. "11'0
B~ Ю11О'Ч~аые,споеа i! C#'-СQСТQflТ из БУКВliЮlOiего pэmcтpQ (p,tufllk, lc.ck., g1aballl1 т,Д.), а
пр!')сrpа~тlШ ИМS/ii, Tl1nЫ., иМена 'lЛен~в, а также, ~ce Йi'1Т~ГР1о1РО83l'1ные а HVIXi CJ1Ott$ на.:мнaJPТОЯ
+rтo IЩrnjiwению) .с ПРОПИGНbUr ~ (НВnpl1М9p, U:m:sole. Wi.l.t~L..iD<e, system..Wiri:dow~,.
Fоrm.s.Ме5заgеВ'Ох , ~'l:Ste:m, ~t~. Эq.lСliеnt 1,1 Т,Д,).

Dдоб~о)\ ц ~!:ЛЮче.В_Ы:М: ~oвaм publ ic аз tatic. 'этот uепщ Маiп


() имеет один
rra.paмe:rp, RQТОРЫЙ в дщrвoЪfс~ае stмя€То.я: юсG:ItВQМ строк (!> t r i n:g [] а.!ч s).
В-ущстoю:n;oй MffiI,~CI:fТ вОароо обрaliЬYlm. этот<о Шсеи»а Мы обсyщn,ат1. не будем. но
следует за.м~тI.rгь. ч;ro э:roтпара:м.етр' :може--г f1pИШl1'Ъ любое число арl"УМffiПОВ ко­
маfllIНОЙ стрщ;{и(BCf\iGpe ~T уз.на.&ге. нав п~ :к.ним доступ).
~прсугра:мм:н:а.а Jюr1.mа 1ilelloClaas Q.()дерЖЙТСя: в ра:мках м.ain (). Зде.сь КСё
П~дъ..'ЗУет~ юшcr; tJb:nsol~. RОТОpblЙоupеделен в n;pОСТРШtC'гnе имен SY·5tf:>rn:. Cp~
ЩН-РЖef."f1Щ др~'ИХ 'I:1Юliов 'IШ.I имеетс!! ·с~crmй ' зJmМен1' wr i:t~Ыпе ( ) . 1iОТQpъПt.
НaR Bы мо!Щ:ете. дoM.цa"J'ЬCli. посылает T~ строку на С'I'mJдартпС1е устройс1lЮ
;В~Boдao' 8дес;ь же вызывается сал SIЗ~ ,Re,adLl.tJe (J • чт.ООы информация RОмандВОЙ
М1JОlЩ ~~О'Й. е. 2\оде сеанса О'J''lЩЦ1G1. У1зшl StuШо 2005. шжа JThl J-le иазхм:е­
те ~'ЦШ~ <.Eцt~_
ВIЩZJy 1'OI'6. что эдесь мщод ма irl () ()ыpeд~fl, к<Ш мe:roд. воз~pamaюnщй. дan~
иые ~ .i;~teger (це-~еlШЫе даниые). перед вы.'tQДОМ п3 метода IЮЭ8РElJЩl~
e'tCJI нуль tранач~ycnemнoе завepmеНИё). Нанонец, :как 'ВЫ можете ПОJW1Ъ
~~Qпр~;цеJЩmm типв. BelloClass, в языне С# .испольэуетсJ'i тот IШД lсо~рие:в,
цр.'ГОp'blЙ был пршmт в С и С++.

Ва,риации метода M:afnO


:Пре~ в;lpиaiп Ма i n () бьш Оllред~лен с ОДНИМ параметром (массивом
C;ТP(l~ я; :в~э~ращал ДЗНJШe T.mm.i1'I t. ОДFIШtоатQ tre единcmeнво воэмoa{ШlЯ фор­
ма Иji iIJ, [) • дли tIOСтр.oщnm Т'OЧЮI wroдa приложеitия МО:nrno И~IIОЛЬ308атъ Jnoбро
ИJ3 ~,p;eд;J..'1ОЩИХ си:rнaтур (о npе,фJOm»Rе'rnи. что она Gодер.житсн. В, рамнаХ{)~I{;"ЩСсэ.
I-ЫIИ о'Пр~енШr C'J"PYЮ"Y.PыJ.

11 ВО1l8р~е.ио:rQ 'D.Шa JII-EI~, масQИa "C~OX а 1QS.ч:8Clt'Зе вpr,yиеи"l'а,


риЬНс .<;:1;..а,Ц с "'9i.d Ма.iл.[ s t r lng-О ~ юgs.)
!
J
r Г.nава З, OCNOBbl языка С# 117
11 ВОS.Р~8JIOЖlО '1!ИD& .8'1', ap~OB В8'1'.
public s tatic void Maio 'O
{
I, )
1/ ВoeJipau~ 'щ!п :in1: (цааое), арХОУМ8В'1'оа S8'1' ..
p:l1bHa sta'.ti о int Main (J
!
i

Замечание, МеТt)Д !'1ai n () МОЖНО также определить, как pr ivate tч~стныи, приватнbiй), а не
рцЫ ic (ОТКРЫТIiIЙ, общедоступный) . Это будет ·Q3начаПJ, 'ПО други~ '1С:ОМПОИОlЮ'Iные бn<Жи нв
CMOтyr HenocpeAcтвeH~Ii;J вызвать ,очку ilХО.цз прилажеtll1Я. В Vlsual Studio i!D05 метод Main I )
прогр!lММЫ авТQматичеСIGI 'Оi1реАеnfl~ТСЯ, lq!К npивэтный.

Очевидно., ч.то при выБОрё. вари:анта оnpедедения .Маiп () :нужно учитывать от­
веты на следующие два ~опрооа. Во-первых, npедпола:I;a~ТСЯ .ли при ВЫnO.J1Нe1I.ИИ
прсграммы обраба:гывать предоставленные nO!1IЬ;3ona:r~ naраметры КQМaнд1J.ОЙ
.стро:ки? Ec.Iщ да. то значения параметров ДО:ЛЖЮ,ц запОМЩlатьсл в масснве строк
Во--вторых. gyЖНО ли будет по за.аерП1eFUШ работы Main () предоставить системе
возвращаемое значеЩt't"? ЕедИ да, то возвращаемым тЩIОМ да.н:ных должно быть
int .. а не \10il11.

Обработка арrументов командной СТРОI(И


Давайте из~еним II:JЩСС НеllоСlаээ так. чтобы он Mor обрабатывать n:араметр:ы
КОМaJЩНой ш·рохи.

11 П'РО8ери'1'Ъ, nepe~aвanкc. .nи lI~eв_ XOМilB ~ОЙ СТрО",


uэiпg S~'stem;

class И еll0Сlаsэ
{
pttbllc .stat:lc int Ma:iin (stri.ngLl args)
{
C.o fis.ole . Wri te.L::\:ne (" ... ...,. Аргумен'I'bl. командНой СТРО1':И .... ** . ,) ;
fQ·r (int j: "" О; i < args.Length; i++.}
е0пsоlе .Wri teLine (" Аргуме'Н!]/ .: {О I ., r aLg$ (i] ) ;

Эдесь с ПОМОЩЬЮ СВОЙСТQа tепgthобъеICТa 'Syste.m..Array провеРЯ~.Я j содер­


жит ли массив строк RaIФе -либо эле!4еНТЫ (КаН вы убеДtiтесъ в далы-I~ем. все
Щ~СИВЫ: i! С# на самОМ деле' имеют 'rJttJ System.J\t:ray и таким обрftЗOМ lJМеют об­
щее множество 'Ч.iIеНQВ). В реаулнг.ате црохода по всем элемен'1,"ЗМ .1Щ(CC}fВа их 31:Iа­
ч~ниЯ 1JБIВ(jДltrся :в ОКН(!) КОН:СО:1IИ. Apryмeвты В командной строке уш\зывaIOТСЯ тан.
иак ПI~казано на рис. 3·.1.
PI«:. 3.,1. АргумеН~ЫВЫЗО1Щ ,fТIi)и'ПQ~НИЯ '6 К!ЭМ8trдRсЩ 1Щi91(е

Вмест.о {:таIЩaРТНQI\О щщла [,/Д' ДIЩ wreра,ций ШIД JIU1ccивамп вхо.цных строк
МО1ИНО l~ШnОlIЫава.ть КЦЮ'lевое ,\;'Л'О1'IО С# 1:0'.:::еасЬ. ЭТ'ОТ эn:еМСl'rr СIП~СIlоа бу~
hoдроБШJ расс"Ма':tриваты:;,я IЩзm~., lЮ JЩТ вам пример ~() , ИСПОЛЪ3OВaНШl'.

Ij O~a'1'М'1'e 'ВИJDQI~е ИА !rO, 'WШi ирк ИIШОnUО8&J1JQ1l r ' ~Q~e.clt· ,


It иа>2 JrеОбх~ РРОI!IЕ!.Р.а. ~ 1IIaC~&:.
puhli С st~ti-l: i111;. ~in (5t;r:i/щ i 1 атчs)
t

foreacl1 (,5t.ring s .in a3:'gs)


C"JflSro Le. ~tl te.Line (~АР~~МЕЩ:J!~, 10'.} ", -"'};

Након-ец. ~С':ryп К, аргументам :комавдной строка обеспе!'lИRQе'!1 ~eeTaтк~


"ieСk"НЙ: мeroд .Gеt:бt7m.maлrlLitiеl\r9~ {l'B-ша Sj>Э1:'..Е§IJ1'.Еnvirщ.mе:nt, &~Цра.ЩаеМым
ЗВа1{ецием ЭТР,ГО ~даввл.нется .:масСИВ строк. Его первый oomм~нт ~­
руе-г IЩТЩl1I')J: содержащий np}UЮЖ~mrе. а остa.льm..rе ~е:юты JJ 'сМЗ;СОИВfi содержат
ПО O~CТ;I:1 apгyмeнТbJ КDюш'ДнОй С1'роRИ (при З'I'OМ. нет s:еобхOДhМOCТИ оцреде"
JШТЬ Д;1Щ M'e~ДI:!. Mal Q () шtрам,етр в виде мас..сива. CJj;'Po)i).

publ i ,c 'вса tlc iп t: !'!аirl · t3triЛ9" [.] a.cg's)


.1

11 По.JtYЧeние 'iP~И!L'O. с: Д0~ Sу.Ииi. ЕnПrONlliel1t.


s t:r ing [] th;eArgs = К!lvtЛЭIнriеnt. Get-Соnu:цаfidL:lп~~9's () ;
СQП8G];е .W.~i teL.ine ("11)<"1'1:> l( ЦРU:!l!Q~:еНЮ) I f О}", HleAr9s [й] ) ;

J.

и с П,ОЛ ьзsаани е ,apГYMeHJOB комамДНОИ


строкм в Visual S1udio2005
Уi>OН~ЧНЫЙ: ДО',ЛМО.flатель yzшзьmает, apryм~K'Ibl ш>мацдной CТPOfQi DjiI'W Зaдjrcxе
nporpaMldbl. БЩ)QЦ~се I?взработlШ Прилmrreнmr Вbl ''"QЖ6'~ ~. фдarи:комавд­
ноп СТpt!JЩ С дerльщ теCТJ1РGВaншi арограммы. Чтобw: сде.патв 'ЭТа в Vis\lцl StuЩD
20~5_. 8lйncщнщ'емойнЫt Щe.J1ЧGS на пиктоrpa.мме Proper1ies lС.воЙc-rва) BQG;В.e
5оlutiJ.JП Exploreг (Обзор решений) и в:ыбеpR're' BКJ1~ Debug (Оmщд!ЩJ, после ЭТG-
1'0 ~Te ~e з1il'ач.e'Flия apryмeнтoB BnollIe тe:Itcтa Comrnan'd line argUriiE;m1:$
(Aprp.rcm:w R@Ш1JДЦОЙ<С1')Ю1m). рвс. 3.2'.
)
Глава ~. ОСНОВЫ, язы~а С# 1'19
..
- -''-' -' -'- '-
=~--~

'.- .
"

i~
1!!ui6 ,SIIn,AriIart ~--"~-- ~~ /"

I ~t;;~_ 9 ---...
~_...........
''~~:i
, 1

ГD!tJWg J О Sl8'ted!:mlt~ ·Г
! ' - - -- - -- - - - ' ~)

I t ~---'J о SJ8t:w-'A!ItJtA: ! '!


[~
.', .1
t'
1.,-
~ f~ ':it:".;~ ~~~f;.":~~.1.~1
_'С: -=-=,=- ____
-::-:-:::='-:-,~~
li
-I
Рис . 3.-2. Уот.ановка apryмeНToB l(ома~IДНОЙ СТР6Р' а V.isu~1 Stud10 2005

Несколько СnОВ о классе System.Environment


Давайте раесмоТримхласс Sу, st€:Пi.Еnvi:tоnmеht подробflе,е. ЭтОТ щrасс сщдер­
жит рцц ста'ЛИЧеCЮIX членов, .позволяющих :подучить информацию ОТНОlШтелЬ,l:Ю
оперсщ~щWIОЙ сиctеМЬ1. в RОТОРОЙ выпОлняется .NEТ-приложение. Чтобы иmuo­
СТРklРОВЭ::ГЪ возможности aтo'ro RЛ8сса 1 Изме'НИТе метод Ма in ,() I! сор:тветствии со
СДеДУЮЩ~Й логикой.

public s'tati:c int мain (s.trl.ng(] щ:gs)


{

11 ИКФ6р.а:ЦIID( об~ииой c:кc~...e.


СОДЗ91,е. Wri teLine ("'Иcn ользуемая. ОС: j :O} ",
Eт!vironment , OSVer:s i ОП );

11 lCa'1'ЗJIоZ', :а 1I:o~opo. иаходиor~ ДРЮtО..-ии•.


СQП,sо lе.WritеLinе(,'f РекуЩИЙ катаХQ:Г: (О} ",
Ешtir.оnmеn t . CurrentDirect.:ory) ;
11 СпксQЖ ДИ~О.QДО. И~ да.ивсЩ кашиие.
str i ng [ о) dr.Lves = Enviro nment . 'GеtLоqiGаlD~i-'1еs () ;
f 'o t' ( i nt i = О; i < drive-$ .Length~ iH)
Сопsоlе.Writ~tiн-е(ltДиCJ< {О} : jl} ",1., driv e s[i]У;

11 :8ep~ . NEЖ-пnaтФарlA1., 'В1i1П0JIИA_а8 ивН&IIDOiа.


C.0 Tlsole. \iI,t'i te.Li P e (' "БЫПОЛJ,lя..емая :версия •NБТ ' : (О I •• ,
'Environment. Versicl'n} i

ВОзможный вариант вывода ПОКЗЗa:R на PQ:c. 3:3.


'ИО. 8.3. napeMeHIti>I:8 Оtlружеl~И,n 'зэ. рабaroй

ъm: Бу.s-tеm . Ел.vi r:onq; e:rrt '!Ю;Ц'еР~ ОI1:реДt-JJe1JШl PJ: дliIyrих ЧЛ$ОВ, a.tre 'Z'o..IIЪКO
I1редставле нных Б ,данном 11 РИМf:рt: . В :rабл', 3.1 1щRaiщиы пt:IroТ,оры:е mrr-еPf'свые:
свойства. во нettpeмeнн0 зaJ'J'iИЮ1Те вдо~еEl'1'Э.ЦИю' .юcr'F"ramеm:д'k 2.0 SDK. "ЧТО­
бы узнать noд;робпоCnL

т.щ~l4ца 3.1. НеlC'Оторые свойс:rвa S}/s'tem.El1vi rOnIRent

М-a.chl!1etfame ~.lIfЯ ~ маШИН\!!


NewLin6' Символ~реIФД€i l'Ja ~OBY\O С'tрок.у ДЛЯ текущего ClкружеfotИЯ
?toceSSOl:Ct'J:tlIlt Ч~CiJО ПРОЦ~ССQ'pоа, текущей маШИНЫ
,sу:s ,tеПr[ri.rеctD.r:у ПОЛI;IЫй' fiYТb " ои.i:iВМI110МУ катЭJТorY
1} S',H:'N';un9! ИШ! ШЩ\ап(. ~ПУСТ"8ШЕ!ГQ ДilHKoe ПРIll1JОЖetl~1е

Определение классов и создание обьектов


Теперь. 1!отда 8bl знаете () роли Ma;tn (). nереЦцем R " щдв:че DОСТроёнци o(jъеи­
'I'ЩJ. 8'0 оса оБЪеR'IНQ-ОРИeuтиpова.я.RЬ1X ВaЬTh"ЗХ Дl!Л8eтСй чei'k;ое j)aЗ1lFlИе ~ещцу
кла:сС8МIi: 1<1 объентами. Термин 1CJIGGC ЯСIlО,l1Ьау(tТГ.j{, )1)ш tщp!;ДС..леfmJ'i ЩЩЫЩJЩТe/Jlr
ClЮro типа (User-Dclined '])'ре - UD'I), (mн" e'CJIИхо:m're. шШiлона. А терМИI:i фъеlaJ1
(tр~ется: Jl,Ш1 оБС!ЗRaЧетш ЗUЗe.мtIЛяра Jl;oН1ilpeтнoro КJIfiC€a в пЭМвтП. КIIЩ"l~..во~
·ещОВQ n~"" 0 С# обе{;печива.e'l'с'По~юб ~Q3Дания 06ъeR0roв. В <m1ичпе от дpyцm оБЫIl1*
тщ:rориe.RТ'ИpQва:нных языков ('raJ<ИХ Kai(. наприМер, С-н-), в C~ НеБqзмоЖНо РЩJ'м~
сти.n ти:п ЮI.асеа .Б степе. noэтому е.слк.вы IlОПЪ1таёТёСh использtJВа:ть nep~Iн.yIO
класса. tCQ1r0PS :не. была Е:.аздааа с ЛQМОЩЬ!О эеw, :вы пол;,rm"Ге ,ашв.бку ~
Тarщм рбраэом. СJI~JOЩИЙ программ'йЫй КlO;Ц С#' ОRa.зъmaeтt:а ~доПУG·J111.LI\1tьыt;.

u·slng 8уЗ'с:€1!L;

ciass aelloClasa
{.
раЬНс srt:atic ilrIlt мaiд (!':1 t-r~tlg: [J ar'J$)
i
11 OJIIие~f ИсаС)m..)'e':tI~ R~Q8аiпl" лох........
11 ~. ~e'l' Иcnon,ltsо:аёl!"' t n~' .
Глава 3. OCfJ08'bl языка С# 121
И.еIl0сlа·s·s оС1;
е1 . ЭоmеМеthо,d () ;

Чтобы ИСПQ<лъэоватъ правиЛbl:lЫе .процедуры ДIl.Я создания об'ЬeJtТЬВ, внесйте


сле.цvю-щие измеиеИИЯ.

using .l3y.s.t.e.m;
сlаsэ H~110~1<l~$
!
publ.i'C static int Main (sti ing [) arg:S)
I
1/ Момио об'li!D_ И ссз. ._ ос5ИJtт • О~Й С'1'роке •••
HelJ:o.Cla$s с1 = new RеЙlоС:lаs.s () ;
/ I ... ИJ1М, ухаза~ об~"~.JlИе и СОSД&lOl8 • p u _ с!Рроха.х..
B€йlQClass (32;
с2' = new Неl1 o'Class (') :
.. ,
}

КЛючеJlое слово peW отвечает за В'Ыqиcле~е 'Ч)rсла байтDВ, необходимых Д1IlJ


~ада1Шого объewrа, и выделение достаточногоо~ У'щщ:вляемои ДИИaмJ<lчесвой
naмяrrи (managed пеар}. Б данном случае вы раэмещаете д:в~объeкrа '1"1ша юr:асса
Не110Сlаsз. Следует ш:шимать. что QБЪeJqНЫ~ церем:енныё CIt на самом деле на­
ЩПОТСЯ CCbиucaмu нвоБЪеRТ в пам,я;ru. а не Ф~еcmrми Объекта-1IIIЙ. Таж '<{тос1
и с2 CCblI'laIOTCsr вц унииалъ~й Щiъе.К1I't1е110СlаS5. paaм~ в JnpaБ.!LИемо:Й
динамической ТlЗМ.fJТJo1.

Роль КОflСТРУКТЬРОВ
До сщ пор объ~ты Hel1oClas:s строилиоь с ПОМiiШU>1O Т<'P~l!:mpyfCmDpa.. эй.да:юш.­
;Ю' по УМОil1ЧЦНШQ, :который. :00' определению, не }lМeeт ap:ryмeвron. Каждый класс
С# автоматцчесци Сl'щ~жа~тсS:l ТШ10IJ1>Щ понструктором, нотррЪ1Й Qbl МОЖе'.Ге при
.необходимости переоnpеделить, Этот ТИПОВОЙ lЮНСТРУКТQР ИСДО11ЬЗУется по ум:од­
ЧЦНИЮ и гарантирует.. что все ЧЛен&Х-дaщIЫе по умолчаншо ПOJ;IyЧаТ" подходящие
тиnрвые аначения ('1'аУ.ое првед(ЩИе xapa1tl.'ePНO ДЛЯ всех :констру!('щров). Сравните
ЭТО ~ ситуацией s Ct+. где неиящща~ЦiЗироваJ-щъrе двнщ.tе. укаЗbUJ8ЮТ на "мусорМ
(инщда ~едочи ов:аэывщо.тсg· очсщъ.важнымц).
Об~с rq)OMe KOHCTPYНTQpa. задВНJ-fОГО до умолчанию. массы предлaraI01!' и
другие конструкторы. Тем C<lМPIМ .вы обеспечиваете возможность. инициaaдIЗSЦИИ
СOC"I'()ЯНJJЯ об:ьекта щ) цреМЯ et'Q созда.ння:, Подобно Java и Сн, lWHcтpym:oPblB С#
.имеют има.. еоотвеТствующе<: имеf,IИ w;racca, ~оторый ОУЩ RОНСТРУИРyюr. ~ ЩЦllIИ­
](Ot'ДaHe 1Юввращ,аюТ значения (д~e значения vaid). Ниже сно.ва расс~иваетОя
тип Не1l0Сlаsэ, НО' с ПОJIЬЗоватеll;ЬС~ конструктцром. переоrrpeделe:нIO!IМ ЗВДШJ­
~ по умо~анию КOHCТPYКIТOPOM, и элементом ОТЩJЫТЫХ: стрщщl:lЬЦt дВВНр]Х.
11 НeH«Д,~~ о EOJf~leIop2JiIИ.•
w3 :Lйg В\x''5t::ertI/o

clt.s"", itеl10б;1!!~.
i
{l ~_ oa:oqw рек .;11.. . , . . . .

рм tit. s г-:rjn.g\ll$'еd~~~11: ~
/1~op, аqaчRМf.:ео~"
puЬHё J;;'ё ll о l:: iаз'!5 {1
r CoawlE;. !"'~3. t-e1.;:!.x,e ("'!#Ii1З:Е?'f:I ж;;ш;~~:t=uр_, E<dд;a.H~ ПО, Умt'JJ1Чaw.шР ....} ;

п naАаоаа.~ J;O.iiC,..""e~~·, ~lISIID'e


// е ~ D~S(1• .• ~.Я.
* Д~ ~Oc.~

~bl;J..c }IelloCIAliis (stE1Fl,q mз~ 1


f
r
С,QD$Фlе.~.i t ·",I,ll.Li.' "!ШэВ8'В IlI.'J.IН:,.З·~'J!e_;recм'1ЙI !l:t,!~~,!;'l'Q1:'! " ~~ ;­
!i::';9ie:rМe~GВlge = msg,'

// '~ф""' ;iIXQ,1I& пр~.


p El>l;:1 e ~t-..a:t!..>:, int МБ.Ь1 ~sb:in'i1 11 fl'.!·9~.Y
!
11 ·& qqaIt~~, З~' nO~,
l'iellБСНs'Ео c'l '" Jt~w 1JIe-1l0li:.lаэs f.) :
C1\Jn:s-оlе •.Wri ~1i'!!Lj:д:rt!! i "':;!Б&:JJеН'Ие L,Is'€:~ge.: {~! 'Ii.,t'i " r
·cl.~,~ss=~liW1:1 $sil3'e 1·:
11' 8Шав, а.реНfiIIIPНS~~ ·аФ~а,.
Ие 11ф: J" ~$'jii' ,;;'2 ';
r.;;2' -= :!J~ii !j,el1ФСlа,l\3 ("rrРФ'Eiер.1j:а .• 1,. lr з" 1 ..
c·oo&vl.e· . ~lNп ,t.е-ъ.i(l.е {ТfЗIi4<i~&щ'(" \1S..;>:!·~ЗS<Jge, : f 0) '\1] " ,
!:А' .. u'S'.er·~~ag,el ;
'Cm!,s/J le~ ~adliiJi'!.e ,Н
!:'~ t ll1:' t1 {J;

3'ам~.Ю;te.. ЕМи 'M'1-nup~tJsеr "'Л~ (B'.JW'Ia'A ~ :~с1wк'!'!)ры) а' DIro'lщ,iJ(ОРЫМ!,! :иМl:ifl~М/IJ" I'CЮ­
p~ ~ичаюЦ;fI ri)J1blkQ ЧIoffi'Д()jI t l1/.'11'1 i~liItiJlIК1 л~, ~ 'Сr.IOТJ3е1tJJJyIOщ.tЙ ''Wz11 kа3tЮ11l'ЮТ'
'Ii1ВfIeгp~" В rnaae'~ J')~~ 6~T PQ:cql\I'p:rpeffl'.\ ' ГI!if,l:WQt1i.Ю.•

Пра анаj1ие~ ~Q>,Цa. ~lif , ~~ b(~ 'aaмem-rь. "'11m Ш')~lC!l11J"1aор. ~~


ны:it.дo ~~ ДРQ'{.'щm:ц~'F erpc:!!(Gвtn.iy '1'iDJIlIЗ :шачеliн.6 (nYС':I'ое). ~Q .
трemrtil€.па }f).,I[~Ю. И· W в.м1llUil ю;m ~~ 'U!ЛiI:сщрyкrор OnP~ДiUI
ч.1temt SНR'tеюre. ~О~:I1ав.iR.кmю ~сша"J.'eЛeМ fрйс. З.4}.

Эам.e<lаlJМ8. f'rnоле Ot1PecIEl~ nr.;l1.lrЭfJ6ЗТЩlЫQIOOi'1JfroЩ)'ф~ра ,Qftя 'РЮ:;' ~ 101OIfC1'p~. sa-


~al.ffJl>l~ П.О )lМf:i:.m;lОЮОО, :(.:\lA~r ,УАвие~. Llrotlbl, s ~l'OM ' сnуузе у nOj'i~\'.I8~п:е~~ QQbl'КI'ПI. Q.C1'aJl00b
SO~).tHoCJ'b,I W1дВi1ail~ Э~~IЗ)11П1:iЯР1>j ~ИПВ . ~ J1DМnЩЫО II!OftC1'PYIoITOj,14-, эвд!J!:mcJIОО ЩJУМOlIq3J'I\~IO,
T~~ KOlцC~~ ~o IШIЮ 11ереаl1pe.t:!p1lиn.. ШI{ -это t:МI",IlHr:lff IJ~Щем, 1Тj::Ц1Щ!iре,
ГлаваЭ, ОСНОВЫ языка С# 123

Рис. 3.4. Простая логика конструктора

Ут-ечка памSlТМ
Если вы имеете ОlШТ программиро:в-ания на язьucе С++. то У вас в связи с' предм­
дущимипримерами программ:иощ кода МЩ'yr вознmtатъ вопросы. В -частности.
сдецует обратпrь внимание на то. "rro Me'I'O):!; Mail1 (} nrnа HeiloClass не i{Мeeт ЯВ­
ных операторов yt-Iи'tггожеюm ссыJo~~ с1 И <;2,
Это не ужасное УПУЩение. а npaвЩJo .NE'f. 5юс 1-1 прorpаммистзм: VfsuaJ Вastc
и Java. про~мистам: С# 6е требуется YUI1Чтож;ать управляемые об1;.екты явно.
Механизм сборки мусора . NEТ освобощцает память автоматичеСI<Jf. поэтому в С#
не ПQддерЖИJtается кдю-чевое СЛОВО delet-e. В ГJI8:Вe5 процесс сборки мусора будет
расClИотрен noдробlJО. До Toro :вp€меШl 13ам достаточно Знать ли.щь о ТОМ, Ч1'о сре­
да вьmолнения ,NEТ авrrоматически у:fIИ~rтожит размещенные вами ynравляемыIe
объекты.

Определение "объекта ПРИl10жения"


в 1Шстоюn;ее время ТИП НеllоСlаsз решает две ;Jадачи. Во-первых. 'эТот класс
оnpедeJШет roчку входа в цриложeш.tе (метод Main ()). Bo-ВТt1РЫХ, HelloClass под­
держивает элемец:т .дaJПIЬJX и НескOЛЪRО конструкторов. Все эrrо хорошо и синтм­
сически прэвиль:но, но H€Мi{oro стpazlНbIМможет Dощюатьс.!1 ТО> что статич-еС:КИЕ
метод Main () создает Эlt3eмnляр ТOI'Q же КJ1acca, g котором этот метод определен.

class HelloClass
r
pulHic static int Маiл (.st.rl.ng [] ад:чв)
[
Fle1l0Class сl ;: new HelloCl азз О ;

Такой IIOдходадесьи в дрyrиx примерах используется только ДlLН тоГо, чтобы


сосредо'l'O"ЧИ'tЬс.я на JIiIJJ.IOcТpaЦИ решения соответствующей зада--m. Более есте­
ственным ПОДХQДОМ 'была бы факгоризациятипа 1ielloClass с разделе:mreм его на
два отдельных класса: ИеllОСlд.SS и HelloApp. При компоновке G#-приложенил
об:f:iIЧiIО один тип используется в качестве "объекта приложem:tя" (это тип.опреде~
лнющий MeTQA Main ( »). в то время кан остальные типы и составляют собственно
lI}JИ.liОЖеНИе.
-
124 Часть 11. Язык nрограммирования С#

в терминах ООП это называется разграничение обязанносmeй. В сущности. этот


принцип проектирования программ требует. чтобы класс отвечал за наименьший
объем работы. Поэтому мы можем изменить нашу npограмму следующим образом
(обратите внимание на то. что здесь в класс HelloClass добавляется новый член
PrintMessage (».
class HelloClass
(
public string userMessage;
public HelloClass()
{ Console. Wri teLine ("Вызван конструктор, заданный по умолчанию!"); }
public HelloClass(string msg)
(
Сопsоlе.WritеLiпе("Вызван пользовательский :конструктор!");
userMessage = msg;

public void PrintMessage()


{
Console. wri t eLine ("Значение userMessage: {О) \п", userMessage) ;

class HelloApp

public static int Main(string[) args)


{
Hell o Class с1 = new HelloClass ("Эй, вы, там ... ");
c1.PrintMessage();

Исходным код. Проект HelloClass размещен в подкаталоге. соответствующем таве З.

Класс System.Console
Многие примеры приложениЙ. созданные для первых r:лав этой книги. исполь­
зуют класс System.Console. Конечно. интерфейс СШ
(Console User Interface- кон­
сольиый интерфейс пользователя) не так "соблазнителен", J(ЗК интерфейс Windows
или WebUI. но, ограничившись в первых npимерах интерфейсом CUI. мы можем со­
средоточиться на ИЛJПOстрируемых базовых понятиях. не отвлекаясь на сложности
построения GШ (Grapblca1 User Intenace - графический интерфейс пользователя) .
как следует из его имени, класс Console инкanсулирует элементы обработки
потоков ввода, вывода и сообщений об ошиБIiах для консольных приложеииЙ.
С выходом .NEТ 2.0 тип Console получил новЫе функциональиые возможности.
В табл. 3.2 представ.iIен список HeltOTOpыx наиболее интересных из них (но. ко­
нечно же. не всех).
[лава 13 . . ООНОВЫ Slзыка С# 125
Таблица:3.2. ПQдборкв членов System.Col:ls61e, НОВЫХ ДЛ!! .NEТ2.0
Член ОпксaJtИ6
ВасkgтDl1пdс.оlо± свойства, УСУQНВ8ливающие цвеТ изоБJ)Зжен-ия/ФОна Д!1Я текущего пото­
Fо!',еgrоuлdСQlоr IШВЪ!80да" Moryт получатьзнаlitени~ ИЗ nеречl'lЯ C.on$oleColor
B\.if" ferHeig11 t Оаойства, контролирующие вЬ!соту/ширину буферtfо61 области КОНСОЛИ
BufferWidth
a€lax () Метод, ВЫnOJ1l>-lЯIOЩИЙ очистку буфера и облаети ОТCJбраж.еАИЯ КОНСОЛИ
Title Свойстsо, устанамивающее заголовок текущей KOHCOn~
W'inclow8.eigh·t Овойства, контроflирующие размеры I<QНСОЛИ отщ~сителы4o э:аданного
wimdowWiclth буфера
Win,jowTop
Wind:owLeft

Ввод и BblBOA В клаосе Console


JЗдобавО}i н: ЧJl~ УЩ13;ЩНЫМ в табд. 3.2. тщ] C;:onsole опред{!Jlяет МliЮЖество
~eTOДOB. обрабатывающих -вво;дщ 'ВЫВОД, цричем ~pe ЭТ}f методы Опреде.цевы RaR
статичесн:,ие (.static). по~тому 0fU1" 1!ЫЗЫВaIOТС:Я 1ЩУРЩlНе :класса. Вы уже видели.
что WritеLiле () вставляет теJiРТQВУЮ строну (ВКilI9ЧtЦi символ~озврата RaРeткиj
11 ВЫХОДНОЙ поток. Метод Wr i t;.e (} вставлнет ~CТ в ~ЩОДНОЙ ПОТOR без возврата
lШретIЩ. Метод ReadLi.ne' (:) I10ЭВОЩi:е'Т ПОJlуqmъ ив:форыаци1о из ВХОДНОТО потока
ДО символа возврата каретки. а Read () и"пол:ьзуе'l'С:П ДJШ :захвата ОДНОГО символа
я:з входного ПO'Fока.

ЧТQбы D ро~,;;rлюстриро~ать ЬСЯ€lвные возможности вв,ода~въпюда класса


Console, рассмотрим сл~дy1OIII;ИЙ :мeтUA Main () , который запрашивает у пол:ъзова­
теJШ некоторую инфор1\'!!ЩйJO и повторяет каждый элемeвrn в llO'l'O:Re стандартншо
вывода. На рис. $,5 DоRaзан npимер .вьmoлнеmш тmroй щюrраммы.

11 ИсПоm.sоэа,кие )(Лаоса ОоПзо.lе дn;_ _ ОА& И .qOAa.


эtа:t;iс 1(o:J:q Mail1 ($·tring [] args)
{
IJ Э~ м,. Н8l1:0!JtQPWX СШРО1С..
СОlьsоlе.Wхi.tе ("Введите свое иыя: ");
strlnqs = COrr,s 0'1 е . ReadLine (J;
Сопsо1е .• Wri teLi!\e ("ЦРtlEе'Г, {О} ", 5');

Conso1e. Wri.te ("Укаl1КИте В'ОЭРВ'СТ J '1) ;


S = Сопэо~е ..ReadLine () ;
CO!Tsol€. Wr.itеLiле ("Вам [О.} год (а) /ле'I"/, З);

Рис. 3.5. Ввоц и вывод с помощЬю syste.rn.Cons'ole


126 Часть 11. Язык nрограммироваНИR С#

Форматирование консольного вывода


в этих первых главах вы много раз видели в строковых литералах символы {О 1.
{11 и др. В .NEТ вводится новый стиль форматирования cтpOl(. немного напоми­
нающий стиль функции printf() в С. но без загадочных флarов %d. %5 и %с. Вот
простой пример (соответствующий вывод показан на рис. 3.6).
static void Main(string[] args)

...
int thelnt = 90;
double theDouble = 9.99;
Ьооl theBool = true:

/ / :Код '\n' • C'1'pOIC08IIX nитерanах вwпonнке'I.' :ВСТ_lCу


/ / симвоnа перехода на H08YJD строху.
Console.WriteLine(
"Int равно {О} \пDоuЫе равно {l} \nвool равно {2}",
thelnt, theDouble, theBool);

Рис, 3.6. Множество "пустышек» В строковых литералах

Первый параметр метода Wri teLi пе () представляет собой строковый литерал.


который содержит опции-заполнители. обозначеН}{blе {О}. {l}. {21 и т,д, (нумерация
в фигурных скобках всегда начинается с нуля). Осталъ}{blе naраметры WriteLine ()
являются значениями. которые должны быть вставле}{bl на место соответствую­
щих заполнителей (в данном случае этоthelnt. theDouble и theBo·ol).
Также следует знать о том, что метод WriteLine () перегружен. чтобы можно
было указьmать в качестве значения заполнителя массив объектов. Так. строкой
формата следующего вида можно представить любое число элементов.

/ / Замена заПОnНИ'l'"елей э.nекен'I.'аки иассива об'J08Х'I.'О8.


object(] stuff ~ {"Эй", 20.9,1, "Там", "83", 99.999331 ;
Console. Wri teLine j "Мусор: (О), {1}, (2), {3), {4}, {5}", stuff);

Можно также повторять заполнитель в строке. Например. если вы являетесь


поклонником Beatles и хотите построить строку "9, Number 9, Number 9". то
можете написать следующее.

/ / Д-ОН ГОЭОРИ'I.' ..•


Co nsole.WriteLine("(O}, Number (О), Number !О)", 9);
ГлаElil З. ОСНОВЬ! язык-а С# 127

3вмеЧ8Мtt8. Если имеетоя неQоотвеТ~ТflИВ междУ чиtJюм раЗЛИЧНЫI)( заполнителей в фигурных


cr.оБКi!lj( и числом ~ПОЛI{RIO~Х их apryмel'lfDa, то в оред& 8ыполнеRИЯ генерируется искnю.че,
Jiие rоrmаtЕхс;ерtiрл .

Флаги форматирования строк. НЕТ


Если требуется более tложно,е фо:рма:тирование. каждый ЗЩlоонитель может
ДUПОЛШiтeJIЬво содержать различные символы форматироВ8}ЩSI (В .верхнем или Б
вижнем регйстреJ. как п()казано g тafur. 3.3.

Табnица3.З. Симво~ форматирования CТPQK .• NEТ

СиМItОIlW фcp.ta­
Onмcaнмe
пtpOltани" СТРО·

.с или с ИСПОIlЬЗyIO:rся Дiiя форматирования денежных Зf!ЭЧl:JflИИ . По умолчанию пе­


ред ЭТИм $лаГQМ будет размещаться символ ЛQхаЛЫНОЙ , ;ЦенеЖНо:И e.nиН~щы
~cкa*e~, знак домара [$] дЛЯ \).S. EngllShj
Dиnи d ИСlЮJlьзуются дm1 фррматирования де,еяти'jНЫХ \'Iисел. Этот флаг raкже
указывает ~нимальное чисг.tO знвков, ИCfТ.Oльэуемое А/1Я преДСТ~~~IИЯ
'значения

Е или е ИCnQЛЬЗУЮroя для представления в , ЭkспонеНЦИaJlliН(')М формате

Fили f ИОf\ОЛЬЗУIOТСЯ ДЛЯ преДC1ЩlJlения в 'формате с фиксироваННЫМ разделителем


GИЛj.l ,g, 1
Обазtlцчaюr geneтaJ (-общий формат]'). эти СИМВОЛЫ МCJжно использовать
для предстаsneния чисел в Формате с фmСИРОВЭННI>IМ разДелит~!,!М или в
эк~поненциальнаМфармвте
N ИЛl'ln ИСflОru.aylbтся для' базового числового форматирования 1с раэделени:ем
ГРУ"П раэРЯДРВ)
х или х ИспоnьэyI01'СЯ ДНЯ представлеЮ'tя а шестнадцатеринном формате. Если не·
польз~ся Х (8 ,sepXlfeM регистре), то ~ wестнадцатеРИ'ЧНDМ представлении
используются OI1мволЫ верхнеro регистра

СИМВОДЬТ форматирования Дббaвлsnoтcя в виде суфф:ююа :к соответствующему


ЗЩIWIlШ1:гелю 'Через двоеточие (например. {о: G}. ! 1: а}, {2, Х} и т.д. ). ПредпOJtожим.
ЧТО вы добавили в Маiл О сле,цуюIЦЙЙ прol;раммный код.

11 ИCnО&8YQII " • •О!1'ОpJoie А8CJ!pIШШOpJ( фориа!1'4_


static vold Маin(striлgtJ aurq's)
{

:C:ons o le', Wri t,BL i ne ("'ФОРЫЭ'I' С: {O;CJ '" . 51 ~98 9.987) ;


СОnSolе.WritеLinеl"Формат O'9~ {О:В9}", 9999'9) ;
Co'n sole,. Wri teLln~ ("Формат Е: i О, ,:"&},(, 99'9 99.7 БS4 З) ;
С;оns:оlе.WritеLinе('·Формат FЗ: {О:FЗ}"( 99 99:9.9999);
Cansole.WriteLine '''Формат '1'1: (О~N}П, 999 .SJ9~;
СОnSQlе.WritеLinе("Формат Х: (O:Xj'(, 9 9'9'9 9);
СаnSQlе.WьitеLinе{"' Формат х: (O ' :oX~". 99'9'S1 9J;
r
128 Часть 11 . Язык программирования С#

Использование символов форматирования в .NEТ не ограничивается консоль­


ными приложениями. Те же флаги можно ИСПОЛЬ30вать в контексте статического
метода String .Format () . Это может быть полезно тогда, когда в памяти нужно по­
строить строку с числовыми значениями, подходящую для использования в при­

ложениях любого типа (Windows Fbгms . ASP.NEТ. WеЬ-сервисы XМL и т.д.).


I
static vOidMain(string[] args)
{

// Испоnъзо.ание статичесхо~о метода strinq.Fоrшat()


/ / дmr посorpoeииJI НОВОЙ C'J!POХИ.
string formatStr;
formatStr =
striпg.Fоrmаt("Хотите пол учить {О:С} на свой счет?",
99989.987);
Console.WriteLine(formatStr)i

На рис. 3.7 показан пример вывода данной программы.

РМС.3.7. Флаги форматирования строк в действии

Исходный КОД. Проект BasicConsolelO размещен в подкаталоге, соответствующем главе 3.

Доступность членов
Прежде чем двигаться дальше. мы должны обсудить BOnpOC доступности. ИЛИ
"видимости" членов. Члены (методы, поля. конструкторы и т.д.) данного класса или
структуры должны указать свой уровень доступности. Если член определяется без
указания ключевого слова, характеризующего ДОС1YПRость. этот член по умолча­

нию определяется как private. В С# используются модификаторы доступности


методов. перечисленные в табл. 3.4.
Вы, наверное, уже знаете, что доступ к открытым членам можно получить
с помощью объектной ссылки, используя операцию, обозначаемую точкой (.).
Приватные члены недоступны извне по оБЪeRТНОЙ ссылке, но могут вызываться
объектами внутри. чтобы экземпляр мог выполнить свою работу [т.е. это частные
вспомогательные функции).
iвблица3.4. Ключеsые слова С#, указывающие уровень ДОСТУПНОC"rИ

Модкфмкат()р
Описшntе
доступности С#

pl\blit Помечает метод, It8.K ДШПУЩlыil! из объекrной "epeMeHHoJli. в ТЭ-ЮI<Э


!Oi~р.ытblЙ, общедооryпныи) И3 всех ПРОИ3ВОДI-IЫХ классов

р:!: i vate Помечает метод, какдоступныJii толь~ 113 класса, ОПРЕ!деляющего


('"IВ-СТНЫ:Й, приваТJ-LЫй) юот метод,' В С# любой член по уМdлчаflИЮ опрe,lJ,f!ЛЯ-етоя, как
p:c1vate
prcJ-t.еctеd Помечает метод, как доступный AN1 апр-едetlяющего IW1Baca. в' так­
(зarЩllщеНнРli1) же ДlЖ люБО'го проиэводного KJ1acca. ОДНШ<О 'защищеНные меrоды
не доступRЫ из объектной перемеННфЙ'

iпtеrпаl QпредеЛR8Т мето,!)" как достyn~IЫЙ ДЛЯ люБОго Т\llпа ,олыl:o BI:fYТpI1
(В~lугренний) данного КОМПQНРВОЧНОГо блока, нО не снаружи

protected 1 n-t е rnal Onpвдел_Я8Т метод, доступ 'К которому ограflИ~ИВЩПСЯ рамками те·
(ВНУТР~'НН-ИЙ защищенf,(Ы~) кущего КQМПОI'iОВQЧНОГО б'nокэ ИЛИ тиnам\ll, СО3дз.ННЫМИИ3 Оr1ре-де··
ляющеrо класса в данном KOMnOHOBO"IHOM блоке

3аrцищеШIЫе члfшы ока.зывa:IOТ{),fI ПОЛе3НЬL\1.И ТОЛllКО при создании иерархии


:классов, что будет темой обсуждеШUl :rnaвN4, Что Шlсаетсв :внутренних и защи~
щенных членов, то они обычно испо;льзyIOТСН при со:щании библи-оте:к протрамм­
ШiГО Koдa ..NEI' {например. упр-авл.яемЬ!х библио:гек .". dll. что ~e:! обсуждатьCJI.в
:маве 11J.
Чтобы проилл:юстр1Ipовать nри.-•.н!:НeJ1йе унааа:нных EЛlOчевых СЛОВ. создадИм
:класс (SошеСlаsз 1, в 1tOTOPOM ИCnОЛЬауЮтся все уназаЮJЬre МUДlrфикаторы доступ­
ности чле<.нов.

/1 С>цtщиД()C1rymIOсll.'И члеНiОВ.
сlазз БоmeСlаsв

11 Дoc'!!yц~ Вti!ЗД~.
publi с ~юid РЬЬ} i,~МetJlod () ! J

11 Доc:mynен 'J.'олъJtо из ТИПОВ SomeСlаsз.


private void Priv,:i__teМe~,hodO\ )

/I ,дОС'J1YПее из SomeC~ass и nO'!!QlП(OВ.


protected void PrO,teC1;eclMe-tj\JDGI() ( ]
11 ДосшynеВ>r-eЛЬi!J:О в раи1С:ах дающrp ХО:ИnОнФвClЧВОГО Опоц.
iпt-€НlaJ void IntеПJаblеthоd () [}

11 3-а"QlЩeвю.iй ;ЦОС'!!YDЗИУ'1'РИ хомnоновочиоrо б~'О1l:а.


protect.ed irit.erna:l vClid Рг.аtе(~'tеdI!1tеrпа1ме-thod () {f

11 в с. при o-тсу'!!с!l'ВИИ >laИJolX YJ(a!Jаний


11 члены .110 уКOJtЧaJUSZj С'ilИ'1'aD.rСR npиваТRЪDD'l.
void S@meMet"h..<:;,,::i О {)

Теперь, создав ЭJtземплнр ЕЛасса 'Sоm.еС.la.БВ. ПОIlЫl'.aшvlСЯ вызвать Rажды:й ИЗ


его методой. исполъзуа операцИю. О'бозначаем)'ю ТОЧКОЙ.
130 Часть 11. Язык nрограммирования С#

static void Main(string[] args)


(
/ / СоздаетCJI объеJCТ и :а~OJtНSlетсSl ПОInlТжа _ызо:аа ч.nено_.
SomeClass с = new SomeClass();
c.PublicMethod() ;
c.InternalMethod();
c.ProtectedInternalMethod() ;
c.PrivateMethod(): 11 ОшиБJCа!
c.ProtectedМethod() ; 1/ Ошибка!
с . SomeМethod ( ) ; 1/ Ошибка!

Если скомпилировать Э'I)' проrpамму, вы обнаружите. что За1ЦИЩенные и част­


ные члены вне объекта не доступны .

Исходный код. Проект MemberAccess размещен в подкаталоге, соответствующем таве З .

Доступность типов
1)шы (классы. интерфейсы. cтpYК'I)'Pbl, перечни и делегаты) также могут ис­
пользовать модификаторы доступности. но только pl1blic или internal. Когда вы
создаете общедоступный тип (public). то гарантируете, что он будет доступным
для других типов l(aк в текущем компоновочном блоке. так и во внешних компо­
новочных блоках. Это может оказаться полезным только тогда, когда вы создаете
библиотеlty ирограммного I<ода (см. главу 11). но здесь мы можем привести пример
использования этого модификатора доступности.

/ / Этот тип мо.е'1' испоnьзо_атьсSI moбым JCОМnОНО_ОЧJAD( блоком.


p ubl ic class MyClass{}

Внутренний (internal) тип, с другой стороны. может использоваться только


компоновочным блоком, в котором этот тип определен. Если создать библиотеку
программного l(ода .NEТ. в которой будут определены ВNYТренние типы, то компо­
новочные блоки. ссылающиеся на Э'I)' библиотеку (файл * .dll), не смогут увидеть
эти типы. создать их экземпляры или Kal(-TO иначе взаимодействовать с ними.
ХаРal(теристикой доступности, npинимаемой по умолчанию для типов в С#. яв­
ляется internal, поэтому если вы не укажете явно ключевое слово public. то в
результате будет создан внутреНЮ1Й тип .

1/ Эти lcJlaccы MOI'Y!t' иcnодьзова'1!ЬСSI '1!оnько -IIY'1'PИ


11 '1!еJCущего компоновочного бnоJC&.
internal class MyHelperClass()
class FinalHelperClass() // По умолчанию тип будет внутренним.

Замечание. В таве 4 будет говориться о вложенных типах. Вы узнаете, что вложенные типы тоже
могут быть объявлены, как приватные.
Глава 3, O(;!,loabl языка С,# 131

Значения, назнача,емые
переменным по умолчанию
ЧЛ!lliaМ-перемеЕ:НЬtм :классов автоматичесви ЦРU~1JaИВaЮТСj'l ТJQдх.одяпurе аца,
т.regин. лрецусмотренныe ПО умолчанию. 3ТН 8начения ДдН ~oгo типа дaIщых.
СВОИ, но правила их выбора ДОС1:'ЗТ(!}ЧНО просты:

• для тИПа bobl устанашшвает('я значение false;


• чиC1J:UВЫМ Данцым цp:цcBaJ:[Вae.тC& звачеЩi€ О (ruш О, О. е€ли это данные с ПJЩ-
вающим разделителем);

• для типа string устанaвmmaется ЗlffiчеIlИе Iшll;

• ддя типа сЬа.!:' устанашшвается: значение' \0':


• для ссылОЧНЫХ типов устанавливается значение null.
С учетом этих правил проанали.аирyliте слецую!ций прогрaм:J\ll1'I.ыii 1(0)):.
11 ПОЛ. 'DИпа xnacca ПQI!YЧ~ Звач:еним по умоn.,aRИID~
clas:s 'I"est

p1Jbli[; in1; mylf'lt; 11 УСМiЦIaJIJ1ИiВЗ,е'1'CSI pa!lИIIIIIII о.


pHblic g·triпg I'II.yS>tring; /1 УО'1!аиавnизаеORСМ раэН- null.
рuЬНс booi :шуВооl; 11 УС!N.Rцлиааеtt!СJl piUSИJoIМ false.
p1JlJli с ebj ее'!; myCbj; 11 УсмаВ&S1IИЗае!1lС. PaвJD.IН nulJ..
}

Значения, назначаемые по умолчанию"


и локаnьные переменные

Cf1DCeM Iio-друтому обстоит дело тогда, I«Iгда объявляются локальные пер.емен:­


Iiblf!. ВИДИМ:ЪЮ В 'пределах дaннo:ro члена. При onpедепении локальной пере:менной
вы доJtЖн.ыназначитъ ей начальное значение. прежде чем начать ее и.оI10ЛЬ30Ба­
ние, IlОСКО.ш.в:у такая переменнаяне получает В'ача.J:iЪНОГО зааченин по умолчанию.

Нaп:pш.;iер. следy:юIЦШi uporРЮ\IIМНЫЙ JЮД приведет "к mmIБIre компиляции.

11 ОШИбка ЖDlЩШIJЩЮI.! ПереиeщtЦ • ioca.1:[nt' Д~ J;!onyч:мml;o


JI на~иое значение до ее иcnoт.зоааКtOl.
s'ta ti<:: vo:Ld Маiл (s trillg [) arqB)
{
int lQc:alI nt;
CO!'JSole. W.rit eLin8 (100<11 Нlt);

Исправить npоблему очень просто. СЛедУет присsоить переменной наЧaJ1ЬJ:lOе


значение.

11 То nучше: !rепеJ?Ь все А!IЗOJIЪifIW.


static void Маin(з'tr:lng[] arqs)
(
int 10calInt = О;
Ce>n'S'9~e.WriteLin(;) (localIntJ;
132 Часть 11, Язык программироваНИR С#

Замечание. Правило обязательного присваивания начальных значений локальным переменным


имеет одно исключение: если переменная используется в качестве выходного пара метра (это
понятие будет рассмотрено немного позже), то устанавливать начальное значение такой пере­
менной не требуется.

Синтаксисинициаnизациичnенов-переменных
ТИпы класса обычно имеют множество членов-переменных (также называемых
полями). Если в классе можно определять множество конструкторов, то может воз­
никнуть не СЛИШRом радующая npограммиста необходимость многократной запи­
си одного и того же программного кода инициализации для каждой новой реализа­
ции конструктора. Это ВПОJШе реально. например. в том случае. когда вы не хотите
принимать значение члена. предусмотренное по умолчанию. Так. чтобы член-пе­
ременная (myInt) целочисленного типа всегда инициализировался значением 9. вы
можете записать следующее.

/ / Все 3'1'0 хорошо, но 'I13X3R изБы'1'чнос'I1ь•••.


class Test

public int myInt;


public string rnyString;
public Test() ( myInt = 9;
public Test(str i ng s)
(
myInt = 9;
myString = s;

Альтернативой может быть определение вспомогателы{ой функции. вызывае­


мой всеми конструкторами. При зтом уменьшается общее число повторений ДЛЯ
операции прu.cваuванuя. но теперь возникает следующая избыточность.

/I Все равно OC'1'ae'1'cJt избы'1'ОЧНОС'1'Ь •..


class Test

public int myInt;


public string myString;
public Test() ( lnitData();
public Test(string 5)
{
my S tring = s;
Ini tDa ta ( ); }

private void InitData()


( ту! nt = 9; )
r Глава З. ОСfЮjjЫ St,зЫJ(В ,С# 1ЗЗ
Оба 'этИ IfОДХQда вполне леtитИМПЫ. но в С# nО3В(JляеТGЯ ~знцчать ~ле.нам
типа наЧ8..1IЪНЪie значения в рамRЭX деllЛа:рации (ВЫ. наверное. з;н:аете. что дрyrие
объеКТНо-ориентированные КЗыки [например.. С++], не позволяют Тa:I<ую i!IJ:[иц.иа~
ди3IO.(Ию ·членов). В сле.цующем Фрarменте 11рограммнorо I\ода обратите вндмщще
на ТО. Ч'I'о ШIИциали~ацйя может выD$яться и ДШI. lЩУТРeRJЛЦ ooъeKTных ссы­
ЛОК. а lШ тQЛЬКО ДЛЯ числонЪU: типов даnных.

1J Ec:nи ~O OTn,S &TJo<C& О'2! s.кa"f~, 'rIpeдУСИО'1'р8ЯfDD( по ~аSИl),


11 ЭJ1l& 'l'8XВИ1ta позаonяет иs6е.а'1'Ь ПОВ'I'ориой ааtiИCИ JI1)Cl'pёUlМН.O~o
11 хо.ца ИиицkaJlИS<Щlm а X~tiJ.. ICОИС~g:oоре.
cla!;!S T'e st
{
p.tiblic iDt .rпуInt = 9;
pJJbl H :: strin-g mY-3tr = \"}ro е в.ачаЛЬJ:Ю€ ЗR,а, че l;'!Ие. ";
р иЬНе: Spo:rts G.a.r v i pe:r ~ riew .sр0r't,эСа :t (Co lo'r . Red ) ;

3а~ечанме. Иl'tиц~ализаlJИЯ 1Ij,neHOB ВI:ilПDnняется ДО выполн-еН~fI 'f1рограммtlой ЛОГИКИ "ОНI::,ТРУК;ТQ­


ра . Если' ПРI1СВОИТЬ зliачеНIiI6 полю в са.МОМ К'онсrm;кщре, ЭТО оведет на нет инициализauию
члена .

Определение констант
Итах. вы знаете, ЩiR QQЪЯВМ"ГЬ шwеМeю;LЫе Юlасса. Теперь давайте Вl>lilСНИМ. как
ооределmъ дэпньщ, »зменят:ь :которые ~(' преДПOJJагается. для определения пере­
менных с фИКСИРОВандым, неизмеЩIе1>1ЫМ 3НRчением в С# предлагается ключевое
слово cons t .• После Gпр~деJIeНИ.'I~ значения константы .то.бантroпыtка изменить это
значешrе npиводит IC Qши6ке \l\О!!IfДЩIJЩИИ. В о-тличие от е·н. н С# }(J[Ючевое СЛОВО
const НедЬ3Я укаЭ1ЦВать д.r1Я па,РЩv1етров и возвращаемых значений- оно оредна­
щючено ДJIJlGоЗДaнщI ЛОRалъl'IblX ДCЦIFIЫX и дэпfIых УРОННfI экземпляра.

ВажнQ .понимать. что эначеЩ1е. присlЮенное канстанте. :во вреJИЯ 1CO'.мntlJUI:ЦЦI1


уж~ ДОЛ:ЖNО быть ИЗJJeGТНР, цоэтому нонстанту неяьэя mпщиализироватъ объект­
ной есъJJП<ОЙ (значеJ-ше ПОCJJt:ДFreй вычисляется в "Среде ВЫПOJIВеmш).. Чтоб1:>l ПРО "
иллюстрировать ИCnОJ;lliЗЩJание IOnoчевогослова .c ,onst. рассмотрим следующий
тиn класса.

сlаsз Со пstDаtа
r
11 ~а!Jеиие I ПРИCJl&К8а_ое 1tоиС'Ж!аюre I р,()ЛJI[ИО бvи. И.9.еС~JlС
11 80 apeмst xoмmt.n~.
pubiic G:O'! 'Ist з t.riп~ BestNbaTe.aJIl = "T :Lmbe:r wolv,es";
рщ,liс COТl'st dO):lblE Simple-Pl =- 3 .14;
риЬНс сопst bp,o l Tr\:!th = trus;
p-иЬН ё con:S1;. Ью оl Falsity = lТ:nJ:tb;
J
Обратите внимание на то, "ЧЧ'О зна1{ени.я всех констант известны во Bpeм.f.r 1tQМIIИ­
JШЦШi. 11 деm::твитеЛЪНQ. еCJП1 просмотретъ эти константЪ1 С fI(i)МОЩЬJ(!)· i ldasm .€Ke,

L
134 Часть 11. Язык программирования С#

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


как показано на рис. 3.8. (Ничего более постоянного получить невозможно!)

Ffnd Ffnd Noxt


.field pUblic !itatic literal !itriпg BestNbaTealll = "HJlberlllolues"

Рис. 3.8. Ключевое слово const вписывает "свое" значение прямо в


метаданные компоновочного блока

Ссылки на константы
Если нужно соСлаТься на константу. определенную внешним типом. вы должны
добавить префикс имени типа (например, ConstData.Truth). ПОСIЮЛЬКУ поля-кон­
станты являются неявн.о сmаmuческu.мu. Однако при ссылке на KOHCТaнry. опреде­
ленную в рамках текущего типа (или в рамках текущего члена). указывать префикс
имени типа не требуется. Чтобы пояснить это, рассмотрим следующий класс.

class Program
(
public const string BestNhlTeam = "Wild";
static void Main(string[] args)

/ / Печать значений констант, определеlUWX друrиии '1'ИI1аии.


Console.WriteLine("KoHcTaHTa Nba: (О}", ConstData.BestNbaTeam);
Console.WriteLine{"KoHCTaHTa SimplePI: /О}", ConstData.SimplePI);
Console.WriteLine("KoHCTaRTa Truth: {OJ", ConstData.Truth);
Console.WriteLine("KoHCTaHTa Falsity: (О}", ConstData.Falsity);
/ / Печать значений хонстант члена.
Console. Wri teLine ("Константа Nhl: {О}", Веэ tNhlTeam) ;
/ / Печать значений хонстант ЛОJtaJJьно:tfо уровнн.
сопз t int LocalFi~edVal ие = 4;
Console, Wri teLine ("Константа Local: (О)" I LocalFixedVal11e);
Console.ReadLine();
}

Обратите внимание на то, что д;ля доступа к константам класса ConstData не­
обходимо Уliаэать имя типа. Однако класс Program имеет прямой доступ к констан­
те BestNhlTeam. ПОСliОЛЬКУ она была определена в пределах собственной области
видимости класса. Константа LocalFixedVal11e, определенная в Main (), конечно
же, должна быть доступной толыio ИЗ метода Main ().

Исходный код. Проект Constants размещен в подкаталоге, соответствующем главе 3.


ГлС\вв З. Ос.~lOвы Азыка С# 135

Определение п'оnей только ДЛЯ чтения


как упоминanoсь Bblnre., значенце. npисваив~емое константе. должно быть ИЗ~
БеСТИО во время КОМnИЛЯ.lU-Ш. НО ЧТО делать, ес:ли:еужно создать неИЗМеннемое
попе, начальное значение Которого будет иавестно TOtJ;!biКO в среде выnnднеl-tuн?
ПредположйМ, что вы создали класс Tire (покры:;mка), в ROTOPOM обрабатыва.етея
эначеmrе ID (}щентйфи~а1'орJ npоиз~одителя. KpQMe ТЩ"О~ предположим. что:вы
ХОТите Сl{Онфиrypировать 'эшт тип :класса тaR.чтобщ в :н;ем подцержива:ласъ пара
известных ЗJ{земmшров Ti те,. ЧЬИ знаЧeJШЯ не ДРЛ,2;}fliЫ ~зменятьсн. ЕtШЙ ИсIЮЛЪ­
зовать кmачевое слово c,pnst. вы по~чите ошибку ~ОМПИJlЯЦНИ. Щ}СКОJII:>RY адрес
объекта в памяти cтaiiОБИТс.н }13~ТНЫМ только в cpeiie BbIJ1DJl:Н.eHI1JL
C'lass Т'1. т-е
1
/I IJocltOnЬxy a~ca оcS'И,Jt'1'О8 о~дe.ruDl'!1'CJI 11 среде UШOJПlеllИR /
11 здеоь иe.nъз. иСпOJ1ЬЗова!1'Ь 1tJDDЧезоs МОЗО 'oonst' !
public canst 'I'ire GQodStone = new Tire(90); // OJDиб~а'
publi c c:onst Tire E''ire'{ear =' Гlew 'ri.re(lOD) (. 11 O\IrиСn,!

publ :ic in.t manu.fa clnreID;


publ.io Tire () {)
p1,lb1i 1t Tire tl.nt l Щ
{ mаJШ:fа-сtоrе.ID = ID;

Поля, доступные TDJlhКO длн чтения, Щ)ЗВOJlfIЮт со;щавать gлементы данных., зна­
че:виn которых осхaIOтся ll~lIзвестными в npоцесс~ транС.JIЯЦИИ, :но о 'которых из­

ве.стно. что они никогда не будут иаменяться после IЦ создания. Чтобы ШIредел.и'I'Ь
поле. доступное тom.KO дла чтеНИfl, использ;'Йте JЩIОЧе:вое слово С# L-е"iiidОhlУ·

clii$ S Tire
.\
publi c :readpp.1.y Tir~ G(,l eJ dStол е = ne.w 'Tire' (90 ) ;
pljb1ic. .:с:еаdoЫу Ti re Fi:r:'e'te.ar = nе," T'i re ( 10 0,) ;

pul's-lic int 1Ilanufactli:teID;


p.t jblic ТНе (,) [ J
pub l.ic Tl r:e (111t. 1D') {mi3.L1,Q fa.o tu:z:'eID = 10;
'}

с -такой МОДИфМЩЩи'ей :ВЫ сможете не ТОJIЫЩ ~IJОЛ;НЯТЬ RОМnИЛЯЦИЮ , но И


гарантироваn.. ЧТQ ПРJil Изменении эначе-цийпоJТeiii Good,St:one и FireY'earB npо­
грамме вы nonyчnтесоо6Щение об оnrnБIre.

static vo'i d Маiл ('s tгiлg'[] ',Н ЧS,)


(
// OID;ибха!
/ / Flenьзя:, ИЗИeJUr.1Ъ З'Иачs.ние ПОдИ I ЦОС'1'упвorОТO.tIь1to Д;ПИ qтеиия:.
Tire t = г,еУ.' 1ir. e ();
t. F'ire Ye.ar = леw Т i rе( ЗJ);
1

1
136 Часть 11. Язык программирования С#

Поля. доступные только для чтения, отличаются от констант еще и тем. что
таким полям можно присваивать значения в контексте конструктора. Это может
оказаться очень полезным тогда. когда значение. которое нужно присвоить доc-ryn­

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


текстового файла или из базы данных). Рассмотрим другой класс, Employee (слу­
жащие), который определяет доступную только для чтения строку. изображающую
SSN (Social Security Number - номер социальной страховки в США). Чтобы обе­
спечить пользователю объекта возможность указать это значение. можно исполь­
зовать следующий вариант программного кода.

class Employee
(
public readonly stril1g SSN;
public Employee{string empSSN)
(
SSN = empSSN;

Здесь SSN является значением readonly (только для чтения). поэтому любая по­
пытка изменить это значение вне конструктора приведет к ошибке компиляции.

static vo id Main{st r ingl] args)


{
Employee е = new Employee("111-22-1111");
e.SSN = "22 2 - 22 - 2222 "; // Ошибха!

Статические поля только ДЛЯ чтения


в отличие от данных-констант. доступные только для чтения поля не причис­
ляются автоматически к группе статических. Если вы хотите использовать значе­
ния дос1УПНЫХ только для чтения полей на уровне классов. используйте I;:лючевое
слово static.
class Tire

public зtаtiс readonly Tire GoodStone = new Tire(90);


public зtаtiс readonly Tire FireYear = new Tire(100);

Вот пример использования нового типа Tire.


static void Main(string[] args)
{
Tire myTire = Tire.Fir·eYear;
Сопsоlе.WritеLiпе("Код ID моих шин: (О}", myTire.manUfactureID);

Исходный код. Проект ReadOnlyFields размещен в подкаталоге. соответствующем главе З.


Глава 3 Оснав;ы ЯЗbjlilЭ С# 137

Ключевое слово static


I\эн уже roворилоаь в .этоЙrщm·е, члены Ю1зссов (и струюур) В С# мщ-ут Ciшреде­
лнтъсн с JЩЮЧtЩЪJМ словом static. В этом случае соответствующий qЩ~Н должен
вызыватьсЯ непосРtЩt1:твенно на ypoВI:Je КJДюса. а не ш<эемnлнра типа. Для и.плщ­
страдии рассмотрим "ЗI:IaJtо:IWiIЙ" т.ип sуstеrn.СОЩ1О1е, Вы уже могли уfiе;.1ЩТЬСЯ,
'по ~eтoд Writ,eI,ine () выэъшает.ся не с об'Ъe1l'ТНОГО уровня.

/1 0IIIи6ка.! W:ii teLine О - .:ио не Jlе'ЮQiЦ уровви ЭX!l8мIшRpа!


COI1Bole со = new Consol~ () ;
e.Wr-:itеLinе ("Та« I1е'Ц·ilтать я не Mo·r'y •.. 11);

Вместо этого НJЖНО просто добави'UЬ Iipефи:кс именитmrа R имени статичес:коJ'G


члена Writ€Liпе ().
1/ Празиm.Но! Wri teLine () - Э~О с'%'а~ео1СИЙ "е'1'ОД.
СDnзоlе. Wri teLine ("·сП,аСИБО ••• "'1 ;
МОЖ:80 СJЩЗатъ, что стаp.Iчесние члецы явл.нются элемeu:raми. щ)торы;е (по мн;е­
нию разраБОiFЧИКЭ тиuа) ОJiВ3f,тнаютсн "ОJШШIЮМ- банaтrъНhIМ]1J", ч:rобы соэдаватр,
ДJПl них экзеМШlflJ>Ы ТЩIEJ.. Ц:р:и созд~ типа класса вы можете (шредел:и:т~ любое
LIИ!.'дО СТCiJ,тических членов J!iJ.и:mJ тцщдов УРОВUЯ:Эi{зeмruщра.

Статические методы
~Сj:Шотрим следующий ШlJЩС Teenager (подросток), который определне'Г ста­
тический M~TOД Complain О. ВО3EiРащающий случайную СТРЩ"У. полученную с I10-
МОЩЫО щ,I30ва Чi';I.стной всдомогателыюй фytцщ1ДI GetRl;ifldomNul)\ber () .

classTeenaqer
{
pri vcat.e s"tatie Rand'cmt r = new Ra.ndсяn () I
private stati.c int GеtF.аn,dоmЫumbе:r !sho:tt uppet.LimitJ
I return r.Next (upperLiimH); .)
publlc sta.tic atrirlg Сощрlаin (:'!
{
:striлgIl шеS;%lgеs = neV.t string 151 f "А почему F!?",
"Он первый начал! ", "Я ~aK устал •.. ~ r
"Еена1!lИЖУ щкодУ! "., "Это ~еч,е С']!tЮ !" } ;
r-et1;lrn m~SGages. t$еtRaлclоrriNuпфer (,5) ] ;

Обратите ,вJil1::мание На то, что "Iiлен"перемениая Sys'telТl.RandplТ1 и метод


GetRaI'J.domNumber ( j. определяющий вcnомогателыryIP фУИКЦЩО, также ОО'I;>ЯВЛены
как ста:rи<Iеские ЧЛЩ:rЫ масса Teenager. согласно прави.тIУ, по которому статиче­
ские члены могут оперировать JТIQЩ:.КО ста:тичеСI\ИМИ qлеnа:ми.,

3аме'IaIlИе.. Позвольте мне·n08ТОfJlo1ТI:.СЯ. GтВТИЧ8Сrnе чдень/ MOryr ВЩlдеАствоват~ roлько.на стати­


ческие члены, Если э статичеСII:ОМ методе вы Г1аПbfтаетеСh 'использовать нестатические члены
(также J,fQзыааемые Д81*/hlМИ уровня Эf(земnляра)~ вы пол)''ЩТе оши:бку КОМпИЛЯЦиИ.
138 Часть 11. Язык программирования С#

как и в случае любого другого статического члена. чтобы вызвать Complai n () ,


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

/ / Вызов статичеСRОГО метода Соmрlаiл класса Теелаgеr


static void Main(string[] args)
(
for(int i = О;i < 10; i++)
Сопзо1е . WriteLine ("-> (О}", Teenaqer.Complain(»); }

И. как и в случае любого нестатического метода. если бы метод Compla in () не


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

/1 НестатичеС1СИе дaннwe AO.J1I1:Иbl вызываться на об'ИlJCТНОИ уровне.


Teenager joe = new Teenager();
joe.Complain() ;

Исходный код. Проект Sti:lticMethods размещен в подкаталоге , соответствующем главе З.

Статические данные
Вдобавок к статическим методам. тип может также определять статические дан­
ные (например, член-переменная Random в предыдущем классе Teenager). Следует
понимать. что когда класс определяет нестатические данные, каждый объект дан­
ного типа подцерживает приватную копию соответствующего поля. Рассмотрим ,
например, класс. который моделирует депозитный счет.

11 Это'!' JCJIacc _еет элеиент неС'l'aтичесJCИX ДaJUIWX.


class SavingsAccount
(
public double currBalance;
public SavingsAccount(double Ьа1апсе)
{ currBalance = balance; }

При создании объектов SavingsAccount память ДЛЯ ПОЛЯ currBalance вы­


деляется для каждого экземпляра. Статические данные, напротив, размещают­
ся один раз и совместно используются всеми экземплярами объекта данного
типа. Чтобы привести пример применения статических данных, добавим в класс
SаviпgsАссоu п t элемент currlnterestRate.
class SavingsAccount
{
p1.lblic double currBalance;
public static double currInterestRate 0.04;
public SavingsAccount(do uble balance)
{ currBalance = balance;}
Если 'reIrepL создать три экзем:nляpa S'9.vingsApcoU;rlt, ICaR ПОЩ1Зан~ ниже

st.at{c -.тоid Main tt>tring [J args}


{
11 kaJIcдый ОбrJ.eХ!l1 SаviпqsAcСОlШt веет свою JltОПИЖ/ ПOШ!l currBal.ance.
S:av±ngs.f!;ccount з1 = new SаviпgSАССО\l:nt. (50) ;
8avingsAc.cO!;;ll.lt '82 = 118W SavingsAcc~.nt (1ОО) ~
SavifLgslI'ccount 53 = nе", Sаviпg.sАССОi)лt (10000. 75);

то размещение ДЩIНblX в !ЩМНТИ ДОilIжgQ БМTh примерно таким. к<щ noкaaaHO на


рис, 3.9,

SаViцgЗАtСОUJ1.t: $1 ,

~
c'urrBalance=5Q

sa1fingM\'CCOUrit: g2
I curr Iлtеrев t'Ra te=. 04
tt!frВаlЩ'\GЕ!=100
,
I
-
$8vint)Mccoun.t : 1;3
c:urrВalance=10001J.75
/
, _.:. -,,'
Ркс. 3.9. Ctатические данные совместНо. испо.lIЬЗУЮТ-СЯ всеми
экзеМnлярамиопре.дenяющef'о .их класса

Давайте обноnим класс Savi!lgsAccOUht. оnpe.целив два статических метода д.тrл


nолучеRИ~.и устано1'lШ1 зnачений npоцеитной СТaDRИ. Как БЬiЛО замечено выше.
статические Мe'I'оДЫ могут работать l'О.lIЫЮ со стаmчесRИМИ данными.. Однако не-­
cтanJчесЮiЙ метод. может иеполыюnaть ШU\ статические, так и нестатичесmIе дан­
нъre. Это -имеет смысл. пооко:лъку статиt.rесItИе дm-щые.доступны всем экземплярам
ТЩJа. С УЧf1'roм этоrо давайте добавим еше два метода ypoB1-1Я ЭJCзeмnлnра, :которые
будУТ ИСШ)JIЬЭОватъ переменную npоцентНОЙ ст-авки.

class: S.а1lin·чэАсСФ\JIпt
(
риЫ i tdouble сU.rrЕаlщпсе;
public st<itic double ca=:rnt.e~estRabe = 0.011;
p:UGlic Sаv:LпgS~ССОUElt Idcшblе Jэ.aJалсе)
( <;щ r rВаlад с.е = Ьа} ап-се; J
11 СТiI!.rичеежиа кетоды поnуqeJUUJ/УСТавовхи проц-.иоЙ li:'l'iUХИ.
public stat.ic void SetInteres,tRa1'.e (double леwRаtе)
( cllrrIoteres'lRate = pewRate; J
public $taUc .double GetlnterestRate ()
( retucrn СdrtIпtеrез.tRаtе; )
11 Мewoд:ы Э.ЕЗeмzшиp8 пonyrrеиин/УС'l'aRОВ«И
11 '+Iе](}'ЩeJ4 npoце,в:-'J:',!;!'оJ;i СТ&вICИ.
public: void SetJnte:rj'j$tRateObj (do1jble newRc.te)
[ currln'terestRa·te = 118wRate; f
р u1:Й,lt:: double .GetlnterestRateObj О
( return currInterestRate;)
-
140 Часть 11. Язык программирования С#

Теперь рассмотрим следующий вариант использования этого класса и соответ­


ствующий вывод, показанныйна рис. 3.10.
static void Main(string[) args)
{
Console.WriteLine ("*** Забавы со статическими данными ***");
SavingsAccount 81 new SavingsAccount(50) i
SavingsAccount в2 = oew SavingsAccount(100);
/ / Получение и установха процентной ставки.
СОПSОlе.WritеLiпе("процентная ставка: (О}",
sl.GetInterestRateObj (»;
s2.SetlnterestRateObj (0.08);

/1 Соз~аиие HOBoro об~хта.


/ / Это НЕ • переустаиавливает' процеитнух! ст&Вху.
SavingsAccount 53 = new Saviog5Account(10000.75);
Wri tеLiпе ("Процентная ставка: (О} ",
Со пвоlе.
SаviпgsАссоuпt.GеtIпtеrеstRаtе(» ;
Console.ReadLine();

Рис. 3.10. Статические данные размещаются один раз

Статические конструкторы
Вы уже знаете о том, что конструкторы используются ДЛЯ установки значения
данных типа во время его создания. Если указать присваивание эначения элемен­
ту статических данных в рамках конструктора уровня экземпляра. вы обнаружите.
что это значение переустанавливается каждый раз при создании нового объекта!
Например, изменим класс SavingsAccount так.

class SаviпgsАссоuпt
(
public double currBalance;
public static double currlnterestRate;
public SavingsAccount(double balance)
{
currBalan ce = balance;
currInterestRate = 0.04;

Если теперь выполнить предыдущий метод М а i n () . вы увидите совсем дру­


гой вывод (рис. 3.11). Обратите внимание на то, что в данном случае переменная
cllrrlnterestRate переустанавливаетсл каждый раз при создании нового объеI{та
SavingsAccount.
r
I
rJ13B3 З,. ОСНОВЫ !'Iэыка С# 141

Рис. 3.11. ЛРИСВI\и-вание ~на!iенI/JЙ статическим даНtjЫМ


8 KOHG'rPYKTOplJ "rтереустанаВЛl'!вае-r" эти Зt'JачеНmiI

БыI всет.ца можете устанОliliИТЪ на~а;лъное зшчение сw.тическихдз!uIых. I!JСПОJ1Ь~


зуя. сШIТaRCИС ИlUщиализзции ч;ле~. но что делать. если знзчеltи-е .моЯ статич~­
C'l<ИХ Дaиl-I1aX нужно IIОлyчи:tЪ }f8 (1a~ы данных шш внешаеrо файла? Для реmеmrя
таких задач требуется. ЧТQбь'I13 KOHTeRC-re метода МОЖНО было ИCI:юлъэоватъ соот­
ветствующие операторы IIРОГР~ОГ() ROда. По этон причин:е в С# ДQпускается
определеnие сmamцчеСIC020 fCQнсrпрук:rru:;pа.

class sаvinяsА'СС(JШlt
{

11 С'1'a<rКЧеCJtИЙ'ltОНС'1'рY1t'1'ОР.
sta tic S-аvings,АС'СОuht (')
j
CODsole . Wri teLi:n.e (П В .СТC;lТ'I>Dчес,ком I';OHC'J',pY~To.P6. ") ;
сдrrlntеrеgtRаt:е = 0.04;

Вот несколько интересных зa;r.fечaнШi, 'lЩсающихся стат.ических J(OHCTpy:m'0pOB.

• Л:ioбоЙн.ласс (й.Л:й CТP)l1(тypa) МЩI~ет опреде.лять толькm ОДИН статический КОН­


структор.

• Статический :КОНструктор вьmолняется тодъко один ра., . независймо от ТОГО,


QКОЛЫЮ ооздается объектов данного тпnа.

• Статическиj{ liOH.CTpYКTOP не может иметь модифИНзторов ДОC'I}'ЩlOсти И па­


piIмeTpOB.

• Среда выдолне\IИ!l в,ызыйе-тT СТ!lТlfЧeСкиИ КОПСТРy-Rтор. !ЮI'Дa соз~ае1'СЯ ЭК­


земwнrp масса, или церед тем, Imlt ШШУЧИТЬ доступ }( первому Bы3ывемр:му
С'1'аnrческому ЧJl~ о

• Отатичесttин :КОНстру1<тор ВbI110.тшНeтi~я до 'Выполнения .rпoбоrо1tоНC'tpуктора


уровня ЭRЗeмIJJlЩ)а.

Теперь значение статичеOlЦ<JjX. дапRblX при создании новых объектов


Savil1gsAC"C"dUnt с@Хранпется. и €ортвет'СТВУЮЩИЙ вывод БУдеТ идентичен nCН'Ш­
занному на рис. З.10.

Ст'атические кnЭ.ССЫ
ЯзЫR С# 2005 расширил. область ПРЩ\а'енеюtя ЮUoч.евого С.iЮВЗ static путем
введения в рассмотрение crл.c:vпuч.ес~ клаСсов. Korдa:кп.acc опредмен. :((аХ стати­
ческий. он ile допускает создания Э1Ремrrл:яР0В с ПIЭМОЩЬЮ ЮIЮчеilоrо C;JIOBa пеw И
142 Чвсть 11 . Язык программирования С#

может содержать только статические члены или поля (если это условие не будет
ВЬПIОJllJено, вы получите ОlIШбку компиляции) .
На первый взгляд может показатъся. что IUIaCC, для которого нельзя создать эк­
земпляр, должен быть совершенно бесполезным. Однако если вы создаете класс,
не содержащий ничего. кроме статических членов и/или констант. то нет никакой
необходимости и в локализации такого класса. Рассмотрим следующий тип.

/ / СтатичеСlCИе lCЛассы могут содер.ать толыtо


/ / статичесlCИ& члены и ПОЛR-КОНСТ&НТIoI.
static class UtilityClass
{
public st a tic void Pri n tTime (J
{ Co n.sole.WriteLine(DateTime.Now.ToShort TimeString());
publ i c st a tic v o id PrintDate ()
[ COn SOle.Wr i teLine(Da t eTime.Toda y .To Sho rtDat e String());

При наличии модификатора static пользователи объекта не с,Могут создавать


экземпляры UtilityClass.
st a tic v oid Маiп(striлg!] ar g s)
(
UtilityClass.PrintDate();
1/ Ошибка Jc:ОIШИJlRЦКИ!
/ / НелЬЗR создавать ЭJc:земnлJtpIoJ статическиХ lCJ1aCCOIJ.
Utility Class u = n e w u t ilityClass( ) ;

До появления С# 2005 единственной возможностью для запрета на создание


таких типов пользователями объекта бьшо или переопределение конструктора. за­
данного по умолчанию, 'Как приватного. или обозначение класса, как абстрактного
типа. с помощью ключевого слова С# a b stract (подробно абстрактные тЩIЫ об­
суждаюТСJI в главе 4).
cla s s UtilityClass
(
private utilitуСl аэ s() {}

abstract c las s UtilityCla s s

Эти конструкции по-прежнему доступны. но с точки зрения типовой безопас­


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

членов в определении класса.

Исходный код. Проект StaticData размещен в подкаталоге, соответствующем главе З.


Глава З" O~HOBЫ изыка С# 143

Модификатор_ып'араметров методов
Методы (и статические. и УР(}IЩ.Я ЭJщeмплiiра) могут исп{ЩЬ.зоватъ параметры.
передаваемые вызывюсщей сторonо.й'. Однако., в О1lIИ'lИе Q']; яекО1'орых друтих яЗы­
ков цро.граммиро.вa1lИИ. В С# предлагается Мliржество МDдифи:ка1'ОРОВ naраметрьв.
которые RОЦТР(ЩИРУЮТ способ передачи (ц. возможно, возврата) .аргументов ДЛЯ
дшпtого метода, кaI< n.о.казано в Табл, 3.5.

Тaбnицl!l 3.5. М'О'ДИф1-1каторы naраметров С#


'МОДИфикатор
napaMeтp08

(н'ет) ECJ1j.1 парэ:метр не ' помечен МО,Q,ификатqром, то пр.едполагаетоя передача па­


раметра no значению. Т.е. В.blзыва6МЫЙ метод по,nучит ко'f1\1ю Щ:>.\'1ГИН!У1ЬНЫХ
дaнг.tыx

Qut 8Ы)(ОДНЫI;I пвраметры УGniН<Шливаются выыыwемыыM методом (Н. таКиМ 06-


раз~lVI. передаются по ссыпке). Если ВI:lIЗы:вавмый метод !Не irl8знаLiИТ BbIXOA-
ные параtAeТры, ГЕЖерируетс~ ОШl'1бка компиляции

ПОЗ80ляет переелат!) ПРОИ3ВОl1~ое число аргумеН1'Р!iI ОДИlfаКQВQГО типа 8


виДе единого параметра. Для любого метода :nО(1)'скаеТСSП(lЛЬКО ОДИ~ моди­
фикатор pe.rams И TO:ll.loKO Д1IЯ tlОсл.еднеrо параметра меюд!i

ref СоотвеТСЛ\УIO:I.lЦее значение задается ВblЗhlваlOщей стороной, но ВЪtЗЫВав.­


мь!й метод ,.юже~ это знаLlеl~Lillе изменить (ГJQСI'ЮПЬКУ naHtIble передаются
по ССЫJ1l!:е). Если BbI<3blSOOMQI!:1 метод не nРИОВО!1'Т . ЗН~'iение параметру re'f.
ошибка компиляции не гвнерируеТСi1

способ передачи параметров..


иопользуемый по умолчанию
ло умолчанию napm.le1'p передается n фymщиrQ ПQ' ЗfЩ~J1.I.D(I. Попросту говорн.
еСЛй не определить ЦЛЯ a:pryмeHTa МQД~lШатор, то в ф>'Н,Кцию передаетс.я К(iIIИЯ
перемСI-ПIОЙ.

11 До УИQnUИИJO арryнeив.r neреДiUn'СIi по sиачеИИl>.


publio э'tаtiс in.t Add.!i'tlt х, iлt у)
{
int алs = Х + у;

I/ ~II CJ1iopoн.a не yaJQ.'lWJ! З'DQ( mlме,иений,


11 пос-ttOn"JIУ НОRИ4IицPSpУe'rСII ХОI:ЩJr
11 DриZ'ИВil.DЫD,IXI ~аиИNX.
Х. = 10'000;
У = 8ВНЭ8;
ret.uit:Jl апэ;

Эдесь в,,"шдные цеЛОЧИс'i'JеННЩе п~раметрЪ! uередаются по авачeБИID. Поэтому,


если изменить значения napame-rров в:вyrри дaннo1'9 метода. 'го вызывающая сто.­

рона об этом не узна.ет. na~О.lThКy .ИЗМt;НЯЮТС.я а:ьrачен~ кОПИЙ цеJIDчислеяных


д;nmых ВЫ3Ы8aIOщеГ0 объекrrа.
r
144 Часть 11. Язык программирования С#

static void Main(stri ng[] args)


{
int х = 9, У = 10;
Сопsоlе.WritеLiпе("До выз о ва: Х: {О}, У: (l}", х, у);
Co.nsole . Wri teLine ("ответ: {О}", Add (х, у) );
Console. Wri teLine ("После выз ова : Х; {О}, У: (l}", х, у);

Как ВЫ и ДОЛЖНЫ ожидать, знач.ения х и у остаются теми же и после вызова


Add ().

Модификатор out
Теперь рассмотрим использование параметров out (от output- выходной).
Если метод определен с выходными параметрами , то необходимо назначить этим
параметрам подходящие значения до выхода из метода (если этого не сделать, бу­
дет сгенерирована ошибка компиляции).
Ниже для иллюстрации предлагается альтернативный вариант метода Add ( ) ,
использующий С#-модифuкатор out и возвращающий сумму двух целых чисел в
виде выходного параметра (обратите внимание на то, что возвращаемым значени­
ем самого метода теперь будет void ).
/ / Выходные параметры задaJD'l'СЯ чnено",
public static void Add(int х, int у, out int ans)
{
ans = х + у;

При вызове метода с выходными параметрами тоже требуется указать модифи­


катор o ut. Локальным переменным. используемым в качестве выходного параме ­
тра. не требуется присваивать значения до их использования (эти значения после
вызова все равно будУТ потеряны) , Например:

static void Main(string[] arg s)


(
1/ Нет необходимости задавать значения
/ / JlОJC&7iЬJU.IИ выходным перемеНlDoDC .
int ans;
Add(90, 90, out ans);
Conso le. WriteLine ("9 0 + 90 = (О) ", ans);

Этот пример предлагается здесь только для иллюстрации: нет никакой необ­
ходимости возвращать значение суммы с помощью выходного параметра. Но сам
модификатор out играет очень важную роль: он позволяет вызывающей стороне
получить МножесТво возвращаемых значений от одного вызова метода.

/1 Воавращение иножес!1'В. выходных парамеТРОII.


public static void FillTheseVals(out int а, out string Ь, out Ьооl с)
{
а = 9:
Ь = "Радуйтес ь своей строке .":
с = trllei
1 Глава 3.. OCfloebl ~эыка С# 145
ВJ;>13рШaIOЩая сторона может вызвать этот метод следующим образом.

s1:.,atw voi'd Наln '(st rin. gIJа r gз)


[
int- i: st.Iing st:t; bool l~;
FillThl?se\'als \out i, out ,s U:, out Ь);
Console,. Wr j teL:bEls \ "I n't равНо: {О)", i);
Console .W-:JtitеLiо€(flS1:riпg рав-НО: (О}", str) ,;
Со,твЫе. ViJri t-еL i!\е C"J,;o.olean равно; {О 1-" г Ь) ;

МодИф'икатор ref
Теперь ра<::СМОТРИМ1IСПОЛЪЗОВeu-UI~ в С# МОДИф](IКaтора ref (от reference- t;Cbl-
лочный). Ссылочные параметры ЦУЖН!if тогда, Щ}гда требуется ПОЗIIОllИТЬ методу
И3МеНЯть,дадньте. оБЪ1mлеН-J:lliIe:В .контексте ВbIЗов~ (ю.шрИме'р. В фyнmumx сорти­
ровки или обмена даннъiМИ). Обратите lщима:аи:е на различие междУ ВЫХ:оДl:lьщи
и ссhТЛОЧНl1lЫИ па;раметрами.

• В:li/ходные пар~етры не требуеТСjl И){иuиалирирrл~ать перед передачей их


методу. Причина в том. что сам метоД должеl'l присвоить аначеНи;я ВЪnCOДНJ>IМ
параметрам.

• ссы.Ioчныыe паРЩ{e"I'Рhi неоБХодuмо инициадизировать до 1'ОГО. как они будут


переданы .метоцу-. Цричи:па Б тоМ •. что передз.€:Тся С"сылда на 'существующую
перемеНkJyю. Ес:гш не прпсвQИТЬ rю-ременной lf.a,чальнре ,!начение. это будет
означать ИСШ;>:JIьэовawrе неИl-IИЩrализцровa1ПlО:Й nереме,}щQИ"

Давайте npодемоnстри:руем ИСПQЛЪЗование ШI.ю>IевО1'О СJщва ref с .помощью ме-


тода. в котором осущеr;1'ВJtя.ется Dбмен значениями ~Y"'CТPOK.

IIC~~MpDe~.
Swа_ р.str·iйgs (ЕеЕ stril1g $_lz
publ:ic static v-Oici ref s ,trit1g 52)
r
s t-:rl.l;1g tempS-t-r = s 1;
si s2';
э2 = temp!Su;

Этот метод МQЖ}iО вызвать так.

э-t.,tiс voiJj foitain (st:rJ.ngJ J аЮ':;j8}


j
str i 'n 1 ::;= "Церва' >I строка";
S -t.:rln,g ~2 = "BT{J,pa-я стро,:ка";
CO'I'1 S01e.W-r-itе1ih,еl"До, ; {0}, \1 ,. ", 5, 82);
sйарstrings (r~ 8, re' з2);
C,onsols' . W-ri t-eLiпе ("П Q,сле: ! О}, J1] ", 5" 82) i

Эдесь БЪiЭЪШающая сторона щщс~аивает .началЬНое значение лок~ CТpO~


новым данным ($ и 8:2). По завершении вызова SwзрS ·tring.s (1 етрока э содер:IIWТ
3HaqeН1ie "Втьра-я CТPOKa~r. а з2 -, <Щачение "IIeрвая строка".
146 Часть 11. Язык программирования С#

Модификатор params
Нам осталось рассмотреть модификатор params. позволяющий создавать мето­
ды, которым можно направить множество однотипных аргументов в виде одного
параметра. Чтобы прояснить суть дела, рассмотрим метод. возвращающий сред­
нее для любого числа значений.

1/ Возвращение среднего .ц.пR 'нехо'1'ОРОГО ЧИCJIа' значений.


static double CalculateAverage(params double[] values)
{
double sum = О;
for (int i = О; i < values.Length; i++)
sum += values[i];
return (sum I vаluеs.Lелgth);

Этот метод принимает массив параметров. состоящий из значений с двойной


точностью. Метод фактически говорит следУЮщее: "Дайте мне любой набор значе­
ний с двойной точностью. и я вычислю ДЛЯ них среднюю величину". Зная это, вы
можете вызвать CalculateAverage () одним из следующих способов (если не ис­
пользовать модификатор params в определении CalculateAverage (). то первый
из указанных ниже вариантов вызова этого метода должен привести к ошибке
компиляции).

static void Main(string[] args)


(
/I Передача в аиде списха значений, раздеnеВJGIX ЗёI.ПИorAJМИ, ...
double averagei
average = CalculateAverage(4.0, 3.2, 5.7);
Сопsоlе.WritеLiпе("Среднее 4.0, 3.2, 5.7 равно: (О)", average);

/ / ... пnи передача в виде массива значений.


double[] data = { 4.0, 3.2, 5.7};
aver'age = CalculateAverage (data) ;
Сопsоlе.WritеLiпе("Среднее равно: (О)", average);
Console.ReadLine();

Это завершает наше вводное обсуждение модификаторов параметров. мы снова


обратимся к этой теме немного позже (в этой же главе). когда будем обсуждать раз­
личия между типами значений и ссылочными типами. А пока что давайте рассмо­
трим итерационнъrе и условные конструкции языка программирования С#.

ИСХОДНЫЙ КОД. Проект SimpleParams размещен в подкаталоге, соответствующем главе З.

Итерационныеконструкции
Все языки программирования предлагают 'конструкции обеспечивающие воз­
можность повторения блоков программвого кода, пока не выполнено условие завер­
шения повторений. Если у вас есть опыт программирования. то операторы цикла в
С# будут для вас попятными и не должны требовать пространных объяснений.
Глава з. ОСНОВЫ я~ыка с.# 147
в С# обеспечивrotrrся следУЮщие q~rpe итерщщtmные КОНСТРУ'КЦИИ;

• Ц1mл for;
• ЦИЮI foreach/ in;
• ЦИlt.lJ wЬil€';
• 'ЦШUI 00 /:whi 1е.

Давайте раССМQТРИМ Вс.е ука3aЩffiI~ ЩДfСТрукци:и по ОчереДй.

Циклfоr
Когда требуетел ПОВТОРИТЬ бщш лрограмщшго ROAa определенное qnсщ) раз ,
оператор for подходит Д!IЯ этогО J:IY'Щ1е всего. ВЫ можете указа'tь. сI{олы(o раз ДQЛ~
~H DDВТОРИТЫ:Н блоК npотрflМl\Iтого Iюда. а также условие окончании цmwз. Без
лищн:тс объяСнений. ВОТ шrм соответствуюJ.ЦJiI;Й образец син.таКCI«:a.

11 База ДJt~ циж.па.


s tatic void м.а i n (s'tr iлg r 1 a1:gs,)
{
/ / Цt1iреlllеииа& 'i.' ДОC'J'YПКа '1'OaIЪt«) iI lI:o~lI:c!t'e 'зorоrо ~& fo~.
fQr (ibt i = l!; j < 10; 1.++)
{

J
// ЗД$СЪ веремеНИ&JI ' i ' ие,чос'Ж'уIЦUl,.

Все ваши привы'Uц.re приемы использования ЦИЮЮ8 ii С, Ct-J- И Java примени­


мы и при построеJ1ИИ оцераторав f or в си. вы моЩете СОздаваТЬ сложные условил
ОКОНЧания ЦИJUIа, строить бе(;кенечны:е ЦИКilЫ. а та:кще ИС11ОЛЬЗО'Вa'rЬ ключевые
слова goto. Conti [ше и break. .я думаю, ЧтО эта ИТfW<ЩИQН"fi!Ц конструкция будет
вам поняnщ. Если же вам требylOТ('.R дальнеЙ!Пие объяснeщI,fI по rтoвoдY ЮIЮчевоrо
слова for в С#.. jJСIlОЛЫJуйтедонум~ltГanию ,NEТ Framework2.0 sпк.

Цикл foreach
Кmoчевое слово С'# fO.r-еасh. llОЗВО~IНет повторить 0лредеденпые действия для
всех элементов MCj.~cl!IВa без необходимости ВЫ$JСЛfНИЯ разм~р.ов массива. ВОТ два
ПРJiмера Ис;ПОЛЬЗО:вaI01я f'orea.cn. один ДЛП маСШIВа CTPort, а дpyrdЙ- рдя массива
Цe.iIЬШ ЧИС~ .

11 Прохождение III&ссиза .о nOMOIIItЪJO :foreaoh.


s .tatic "91а Ma,in (stliiлg (] arg.s)
f
sti:in.g [] Ь,юl!;s = [ " ' \:дожные алгоритмы",
"1fJIaCCYNEotKa~ ТЭ>:J{Q.i10 ГИ;Я СОМ",
"ЯЗЫК с# и п'Лii!Il форм а ,NET i ' [;
for.~ac~ (strinq s lJ1 Ь.сюks )
СОЛsо1е. v,riteL1Tle (5) i

int [1 mу!пt.s = { 10, 20, ЗQ, 40 J:


tore.ach (int: i in :rt1'Ji'1пts)
'Consol е •.Wr i j:>eLi..rH:~ ( i) :
148 Часть 11. Язык программирования С#

Б дополнение к случаю простых массивов, f o reach можно использовать и для


просмотра системных и пользовательских коллекций. Обсуждение соответствую­
щих подробностей предполагается в главе 7, поскольку этот вариант применения
кmoчевого слова for e ach предполагает понимание интерфейсного npограммирова­
ния и роли интерфейсов IЕпu rпеrаtоr и IEnumerable.

КОНСТРУКЦИИ while И do/while


Цикл whi1e оказывается полезным тогда, когда блок операторов должен вы­
полняться до тех пор. пока не будет достигнуто заданное условие. Конечно. при
этом требуется. чтобы в области видимости цима wh ile бьmо определено условие
окончания ЦИ1\Ла, иначе вы получите бесконечный цикл. В следующем примере
сообщение "в цикле whi1e" будет печататься до тех пор. пока пользователь не
введет значение "да" в командной строке.

s ta ti c void Main (s tri ng [] args)


(
string userIsDone = "нет";
1/ ПрОlSерха на соо!t'Зе'l'С'l'lSие строхе в нижнем регистре.
while{userIsDol'l e.To Lower() != "да")
{
С ол sоlе.Writе("Выудовлетворены? (да] [нет]: 11);
userIsDone = Console. Read Line();
Console. WriteLine ( "В цикле while") ;

Цикл do / while подобен цикпу while. как и цикл whi1e. цикл d o/ whi1e исполь­
зуется для выполнения последовательности действий неопределенное число раз.
Разница в том. что цикл d o /wh i1e гарантирует вьmолнение соответствующего бло­
ка программного кода как минимум ОДИН раз (простой цикл while может не выпол­
ниться ни разу. если условие его окончания окажется неверным с самого начала).

stati c v o i d Main(string[] arg s )


{
string userIsDone = "" ,.
do
{
Co nso1e.WriteLin e ("B ци кле d o /whil e ");
Conso1e.Wr i te ( "Bw удовл етв о рены ? [д а ] [ нет]: 1');
us e rIsDone = Co nsole.ReadLine();
}while(userIsDone.ToLower() ! ~ "да"); 11 Обратите ISнимание
/ / на 'l'ОЧJCУ с З&ПJI'l'ой!

Конструкции выбора решений


и операции сравнения

в С# определяются две простые конструкции. позволяющие изменить поток вы­


полнения программы по набору условий:
r
l Глава 3. ОСНОВЫ lIэЬ!ка С# 149
• оператор if/else:
• оператор swit; c h.

Оператор if/els.e
в отличие от С и С++. оператор if l e He в С# может работать только с булеШ'!I­
ми "Выраженидми, а Ве с произвольныыи знаЧ~ЩМR -l. О, Поэтому в операторах
it/el.s'E': обычно исщwьэуют.с'я операЦии С#. дон.аЭанНые в табл . 3.6. чтобы полу­
Ч:ИТЬ ОУЮЩ1Lb1;lЬre булевы эRaЧ'еIiИи.

Та~loЩа3..в. Оnераци ~ r;раВI1ения. в С#

Операция
При мер ~о:n ..зоевИИR ОпиcaJlие
сравнения

if (a ge == 3 О ') Возвращает t r lIe (ИD'Гина ) ,ОЛЬКQ в том cnY"Iae,


когда аыаже~RR QдинаКQВЫ

i f ("Fd C> " '= rny:s a ) Возвращав. tr u e' (истина) ,олька в "том Сl1уча~.
~.oгдa вырюкения раЗЛИ'IНЫ

< i f (Ьоп цо; < .2.000 ) 6.0звращает t ru e (истина) ,ОЛЬКО в ,ОМ олу'!ае,
> i f (b OТl US ;. 20'DiO I когда выраЖЩJИе А COOTBeтtтвeHHO меньше,
<= i f ( Ь отшs <'" 200 0 ) болы:uе! меньше или равно., 6оfJьше WliIJ равна
>= i f фQ ПUJS >= 2Q.QП.} выражению 8

Проrpаммистам. использующим С 11 С++. с,ледУe'I' обратить внимание :на ТО, что


их привычные приемы no npоверке уеловий "Jja р@енство нулю" в С# работать
не будут. Нацример. вы xoТl\ITe выяснить. 6уде:т ли данная строка длиннее лустой
строк». Может ВО3J;IИlrn:yть ис:кушение нщmСjЗ.ТЬ. следующее .

/I в С. эта недоnyс'1"ИИО, l.1ocJComoxy Length· 80ЗЗРащае-т з.n t, а ~e .bool .


st~1ng t hо uч hW f'ТhеЬ ау = " С'l' арую с о ба:r<-У I;fО:ВЫМ 'I'рюКiU<I Н~ЧИ'r Ь t10ЖRО ";
i f ( t Л оu g ht:ОЦ'hе. Dау. Len q ,tJ:",)
!

в данном c.nт-Iae ДЛЯ исполъзова:,rIЩl сваиства Str i ng. Lеп g t t. ЩЖЩ>. изменитЬ
УCJ,Iовие ттс . ЕаЕ показано 1:iЩJtE .

/I Э'l'о .цопу~, ~&JtIl:U:' ре8~'l'а'l'фМ будет tl:Ue ~ fа.1зе·.


if ( О ! == t ho uq]зJ:О fТFI'еD а у . Lerl g~ h)

Чтобы обеспечить БCrllее сложную upo:верку. оператор i f может СQДержатъ слож­


иыевырщнени.я и другие QператорI;>I , Сивтаксис С# в данном случае ИДt;:JIтичен
С(Н} и Java {и не CЛИI1l1\ом О'J'JUIчэетсs: от Vlsшtl ВаЮс} . Ддн построения (ц:ф.жных
ВhIpWI~l'ЦfЙ С# имеет вполне отвечающий ожидВRшLl\! набор УСЛОВ1iЫХ операЦИЙ,
011исан;и.н которых предлагаются в табл. 3.7.
150 Часть 11. Язык программирования С#

Таблица 3.7. Условные операции в С#

Операция Пример Описание

&& Н( (age 3О) && (пате "Fred") ) Условная операция AND (И)
Н( (age (пате "Fred") )
" Н(! myBool)
30) 11 Условная операция

Условная операция
OR
NOT
(ИЛИ)

(НЕ)

Оператор switch
Другой простой конструкцией выбора. предлагаемой в С#. является оператор
switch . как и в других языках типа С. оператор switch позволяет обработать по­
ток выполнения про граммы на основе заданного набора вариантов. Например.
следующий метод Main () позволяет печатать строку. зависящую от выбранного
варианта (случай default предназначен для обработки непредусмотренных вари­
антов выбора).

/ / Переaumчение по числовому зиачеНИlD.


static void Main (strin g [ ] args)
I
Console.WriteLine("l [С#], 2 [VB)");
Сопsоlе.Writе("Выберите язык, который вы предпочитаете: ");
string lan g Cho ice = Co ns o le.ReadLine();
int n = in t .Pa rse(l a ngChoic e );

switch (п)
(
case 1:
Сопsоlе.WritеLiпе("Отлично! С# - это прекрасный язык.");
break;
саэе 2:
Co n sole.WriteLine("VB .NET: ООП, многозадачность и т.Д. !");
break:
default:
Console. Wri teLine ("Хорошо ... удачи вам с таким выбором! ") ;
break:

Замечание. В С# требуется, чтобы каждый вариант выбора (включзя default), содержащий


выполняемые операторы, завершался оператором br~ak или goto, во избежание прохода
сквозь структуру при невыполнении условия .

Приятной особенностью оператора switch в С# является то. что в рамках это­


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

Именно это используется в следующем операторе switch (при таком подходе нет
необходимости переводить пользовательские данные в ЧИСЛоВые значения).
Глава З. ОсновЫ ЯЗЫ.ка c:t 151
s'latic void Иаin ($tring l} args:)
r
Co[']s'Qle. WIiteLine ("С# ИJIl1 ·VB"):
СопsоIе.W'тit:е("Выберите q:зыR' 1QОТС:ФЫЙ Бъl лредrюqитает.е·: ТО),

s ,tring lаш~Сrн;)iое = COnSGJ.le . ReadLiNH·) ,;


scwi t:ch (lапgСгюiсе)

саЭе "С#":
С0n:юlе •Wri tеLiпе( "'ОТ:JtИЧt!О! с* - этё I<рекраСI;lЬ1.Й ЯЭb!JiI: ... j ,;
b:r:eak:
C~ эе "VEI":
СОПS'0 1е .. Wri teLi пе .("\m . NБТ: ООП, МI(0 го_заД<l".Щос'rЬ И т .д. ! .. ) ;
break:;
defa.ul t;
Сфо'Sоlе. Wri t eLin5! (·'ХGliЮШG •• , удачи аам с таКИМ ВОООРОМ! 'О) ;
break;

'И~ХQДНblЙ ко,ц. Проеfa Iteration$AndPeois'iQl15 размещен в пощ:аталфге, еоответt;ТВующем главе S.

Типы, характеризуемые значен' иями,.


и ссы,лочные типы
Подобно JlЮбому другому язьщу программЕРОВ<1НИй, язык С# оцре-делнет ряд
нJдoчс8ых СЛОВ. предС'тавляющих баЗО5Ые типы данных. такие RaК цельте ЧИCJtа.
символьные данные, Ч1ICJ1а с ПЛавЩОЩПМ деснтичнымраздemпenем и лorич.еские

((jyJleBbl) значеНFJI. Ег.ли вы работсщи с 8.Зbl1!iQМ С++ .ТО БУДeJ1е рады узнать. что
эдесь, эти 'ВНyrрemше 'I'щlы1 я,вJL"IЮТС.R "фиксированными 1<O}{CT~Taмl"". Т,е., I:1anpи­
~ep. после создания э)tемента ЦеЛочщсленных данных все Я3'blJ(И .NEТ будут пони­
мать природУ ЭТОГО типа и .диапаЗО1;:I его значений.
Тип д;aннъrx . NEТ машет либо ~рalcrеризова'I!bся змчеuи.ем, д-ибо бы:rъссыло'С{­
ным типом (-т.е. хаРaRтеРИ30В</.ТЬСJiсCБIJшоИl. К типам. харантери.зуемым значени­
ем. ОТНОСЯ:ГСЯ Все ЧИС)tо.вьre тицы Д3RНЫX (int, flQat и т.д.), а 'также перечни и
структуры. размещаемые в стеке. ПОэтому типы. харакТt:pдзуем:ыезнач~ниями,
можно сразу же удaлnть НЗ памяти, как ·тольн:о они оха;~ьшаю'ГСЯ 1Ше контекста :их
dfIре.цеJreНИЙ.

11 ЦМ'Очи~е,н!QoU> .цаиине xa.p~p~ca: зщачениеи!


public VQid SonleMeth~d ()
i
int i = О ,,
Соnsоlе . Wri teLine (i) ;
11 здесь '!. r у.цa..nО'l'СS kl5 C'1Iexa.
152 Часть 11, Язык программирования С#

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


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

// ДNЯ ТИПОВ, харах~еризуеиых значениями, в резуль~а~е ~aKoro


/ / присваивания в c~eK помещa.J'l'СЯ две незазисимwе переменные.
public void SomeMethod ()
{
int i 9 9;
int j i;

/ / После следуацеrо присваивания значением I i I ос~ане~ся 99.


j = 8732;

Этот пример может не содержать для вас ничего нового. но важно понять. что
,NET-СТРУКТУРbl (как и перечни, которые будут рассмотрены в этой главе позже)
тоже являются типами, характеризуемыми значением, Структуры. в частности,
дают возможность использовать основные преимущества объектно-ориентирован­
ного подхода (инкапсуляции) при сохранении эффективности размещения данных
в стеке . Подобно классам, структуры могут использовать конструкторы (с apryмeH­
тами) и определять любое число членов.
Все структуры неявно получаются из классаSystem.ValueType. С точки зре­
ния фуmщиональности, единственной целью System.ValueType ЯJщяется "пере­
определение" вирryaJIЬНЫХ методов System.Obj ect (этот объект будет описан чуть
позже) с целью учета особенностей семантики типов, ЗадаННых знаЧениями. в про­
тивоположность ссылочным типам. Методы экземпляра. определенные. с помощью
System,Val ue Type, будут идентичны соответствующим методам System.Object.

/ / Cтpyx~ypы И перечни RВЛRЮ'1'ся расширениями System. ValueType.


public a bstract class ValueT y pe : objec t
{
риЬ! ic virtual bool Equals (obj ect obj) ;
p ubli c virt u al i n t GetHa shCode ( );
p ublic Туре GetType();
p u blic virtual string ToString();

Предположим , что вы создали С#-струнтуру с именем MyPoint, используя клю­


чевое слово С# struct.

/ / Cтpyx~yp.ь1 nЛRЮ'1'CJI типами, Ko~opыe хараJC~еризYJDТСЯ зиачениlDllИ.


struct MyPoint
{
риЫl с int х, у;

Чтобы разместить в памяти тип структуры, можно использовать .ключевое сло­


во new, что. кажется, противоречит интуиции, поскольку обычно подразумевает­
ся, что n ew всегда размещает данные в динамически распределяемой памяти. Это
частица общего 'тyмaнa , сопровождающего
h
CLR. Мы можем полагать, что вообще
Гnaва З, OC~1D8DJ ~~-IbIКf! с., 153
nее IJ проrpa1'o1М~ ЯВJIЯ~С1f объектами И ан.аЧёНИН!"Пi. создаваемыМ}! с помощью Q<:W.
Dдшщо в TO~ СiJ}'ЧfЩ. 1j:Щ'Да ореда выnо:zwенип обнару:ж:иваеттиtJ. полученный из
Sуэt!'!mNаluеТуре, В;blПIШН.яется обращение Jt стеку.

11 Все равно ИСПОЛ1оsуе'N!Я C'1'eJ(!


l1УРоiпt р ;: t1ew MyPoi!'Jt () ;

cTpyItrypы могут СОЗДiШа'Гъ~ fI без ИСПОдЪЗ0Вания ключевоrо сдова new.


MyPr>in t- рl;
pl.K z l00;
рl.у = lQД:

Но при ~!СПОЛЪЗОВанн:и ЭТОГО подхода вЫ должны 13IiШО.111:ЩТЬ инициали:;JaДИ19


1IC~ шщеа ДaJ:lНЩX ДО их использования. Если ЭТОI'O не сде.11ать, ВО3НИI<нет ODIffБЩ'J.
1tPМIIИЛящш.

типы' характер~зуеМЬJе значениями, ссылочные


ТИПbl и оператор nрисва ,ивамия
ТenеРЪИЗУЧИТf: слецующий lI,fетqд Mai [l () и рассмотрите его вывод. ПОнаЗаНН:ЫЙ
на рис. 3.12.
.stati9 void Main (B,t L ing [) arg.,)
(
COn$o~e. Wri t~Li Щ! (

"ir,*'" Типы, хара :r;'I'€ри:зуеМЫЕ: зн,ачение~ I сс"Iлiэчныe ТИПЫ *-1< *") ;


Console. W:r it eLit'\~ , (Н'_ > Соз:nа'Ние р1")- J
.муР{)lпt Р! = ОЕ?'" Му:Рсйп ,t () ;
1"1.]1(. = 10 0,;
р1.у=100:;
Сол-sоl.е, W:r..i.t·еЬiпе t" -:.> Орис:ваиэание рl ТI/1Щ7 Р2\П" i ':
MyPoint р2 = р l ;

// Эт о р1,
Consol,e.Writ el,.Ln,e\ "'p l.x = ! О}", 1='l.х) ,;
СО!'.эа 1е . Wr i:с.Е!Liле (П р l. у = (~I} ", рl. у) ;

1/ ЭТР р2.
COJl:Sole. W'ri teLine ("р2 .k = \ О) "1 р2 .. Х) .;
Consol~.WriteLin.t"p2.y ~ /О}", р2.у);

./ / ИЗ'Ь1!еRение р2. х • .31'0 }IE влияе·т на pil .l::i.


Солвоlе • W'r i teLi11e ( "- > Заl04ена ЭJol'ilч·еНИ!il р2. Jj 8.Q. ·,9:0 О") ;
р2. х = ~OO;

11 ВОвС!я печа':!'ь.
COnSQle. W:r itеLiле (" -> Это сн.о·ва ,значения х ..• "'у ;
co.ns.o le.writ€Line!"pl.x'= (Л}", pl.Xjl
CDnsol е. W:r i te1.Jne ( "р2. х. = 1'0 J' ", р2 .•.х);
CODs.ole .Rfl1:Ld:Line !) ;
154 Часть 11. Язык программирования С#

Рис. 3.12. Для типов, характеризуемых значениями, присваивание ОЗНачает букваль­


ное копирование каждого поля

Здесь создается переменн:ая типа Mypoint (с именем рl), которая затем присва­
Ивается другой переменной типа MyPoint (р2). Ввиду того, что MyPoint является
типом. характеризуемым значением, в результате в cTeRe будет две копии типа
MyPoint, каждая из которых может обрабатываться независимо одна от другой.
Поэтому. когда изменяется значение р2.х, значение pl.x остается прежним (точно
так же, как в предыдущем примере с целочисленными данными).
Ссылочные типы (классы), наоборот, размещаются в управляемой динамиче­
ски распределяемой памяти (managed Ьеар). Эти объекты остаются в памяти до
тех пор, пока сборщик мусора .NEТ не уничтожит их. По умолчанию в результате
npисваивания ссьmочных типов создается новая ссьтка на тот же объект в дина­
мичеСRОЙ памяти. для. иллюстрации давайте изменим определеrше типа MyPoint
со структуры на класс.

/ / kласCJol всегда оказwваются: сcыnоЧIWМИ ТИПаии .


сlазз MyPoint / / <= Теперь ЭТО к.nacc!
{
public int х, у;

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


нии (рис. 3.13).

Рис, 3.13. Для ССЫЛОЧНblХ типов присваиваНl-1е означает КОПl-1роваliие ссылки


[naва З,. ОСНОВЫ !rnыка с# 155
в ./tэнном. случае имеется две ссылки на один и тот Же объект в управляемой
дин~~ской памяти. ПQЭТOму. если изменить аначеШIе х () помощью ссЬimtи р2.
то l\fЫ }'Видим, ЧТQ р1. х укажет на измененное значение.

Типы, характеризуемые значениSlМИ и


оодержащие ссылочные типы

Теперь. когда вы чувствуете рааi-IИЦV мещ,ц,у 'ШшiМИ. харaitтеризуемы:мизна­


чением. и ссылочными типами. давайте рассмотрим более сложный nрИМе.р.
Предположим. что ИМеется следующий ССЫJНi'IНЫЙ тип (класс). обрабатывающий
йнформацио:нную IЛpОh-У. которую можно ус'Таповитъс DОМОЩЬЮ 1ЮJ1Ъ3ОВательс:ко­
го :конструктора.

claS5 S'h<;!pelnfO
1
public stIing .iп.fоst.riнg;
I
publi~ Shapelnfd (.s<tri.n g info)
1
t infoString = iпfФ,' }

ПредIIР'ЛОЖИМ также. что вы хотите помесТ1IТЬ леременную этого типа :клас­


са в тЮI С именем MyReet angie (nрямоугоJlыlк)•. хараJ\."ТериэуеМЫЙ значением.
Чтобы ПОЗВОЛИТЬ :ннепщим объектам устанавливать значение вцутреннега поля
Shape1nfo. вЫ ДОДЖRbl сщэдахь :новый KOHCTpyRТOP (:при ЭТОМ гонструктор струк­
туры. эадЩIЩ;IЙ по УМОЛЧIOЩЮ. является зарезервировшllП:.IМ и не доду{:кает пере­
определения:).

at,r'u ct MyRectangle
{
IICтp:Y~TyPa :td:YRecцngJ.e coдe~ ч.ден Ca.tn01iR0:I10 ~a.
publ i-c Shap.elnfo rectInfo;

p'iblic iлt tOPI left, bat1:om, rig1it;


p\lblic МуRе.С'Цhglе (,stri,ng info)
f
rесtIлf!)ll = new Shap.e'Inf:o! info) ;
t ор = .1 ef t '" 1 О ;
b .o ttGm = rig.ht = 100;
}

Теперь вы имееТе ссылчн::ь:rn тип lШУ'FрП тица. харc;t:К:щр:изуемого значе)illем.


И здеt:ь возникает вопрос на миллион долларОв; ЧТО ·СЛУЧИТOfl. еl1ЛИ присвоитъ одну
переМfJннyIOтШla MyRec-tanglедругой такой же перемe.uнnй? С уч;етом тortJ, что вы
уже знаете о типах. характе~эуемых знач~. вы маж~ сдела':l'Ъ прщ!:Идыroе
npедnолож.еНие о :roм:, что целые данные (кэторые ИRС;:IiМОМ деле J.I форЮ1руют FnY
структуру) для ка·ждой переменной MyRe-с1;:.а11g:1е ДOЩКI:i!:il БЫТJ> lJезависимыми Э~­
ментами . Но 'Что МQЖН'о с:казать о внутреннем ССЬ/.iЮЧВОМ; TJnre? Будет ~1I0IШp01Ш-
1-10 полное С:ОСl'OЯНИе этого объекта или будет CKo:tmPOBi:цJa, ссылка на Э1'ОО' обьентl'
Проaнa:uи:эйруйте следующий upoграммный ПIЩ и paCI;MOТPIJ'fe рис. 3.14, RОl'ОРЫЙ'
МОЗl{ет ПОДСIШвать 'npавильпый OТBe'l:
-
156 Часть 11. Язык программирования С#

static void Main(stringlJ args)


(
// Создание первого об~ек~а МyRectangle.
Console.WriteLine(n_> Создание rl");
MyRectangle rl = new MyRectangle ("Это мой первый прямоугольник" );
// Присваивание новому МyRectangle значений rl.
Console. Wri teLine ("-> Присваивание rl типу r2");
MyRectangle r2;
r2 = rl;

// Изменение Значений r2.


Сопsоlе.WritеLiпе("-> Изменение значений r2");
r2. rectlnfo. infoString = "Это новая инФормация!") ;
r2.bottom = 4444;

1/ Print "alues
Сопsоlе.WгitеLiпе("- > Значения после изменений:");
Console. "у! tеLiпе ("- > rl. rectInfo. infoString: (О)",
rl.rectInfo.infoString);
Сопsоlе.WritеLiпе("-> r2.rectInfo.infoString: (О)",
r2.rectlnfo.infoString) ;
Сопsоlе.WritеLiпе("- > rl.bottom: {О}", rl.bottom);
Сопsоlе.WritеLiпе("-> r2.bottom: (О}", r2.bottom);

Рис. 3.14. Внутренние ссылки указывают на один и тот же объект

Как видите, при изменении значения информирующей строки с помощью ссыл­


ки r2 ссылка rl отображает точНо такое же значение. По умолчанию, когда тип.
характеризуемый значением. содержит ссылочные типы, присваивание приводит
к копированию ссьuюк. В результате вы получаете две независимые структуры.
RaЖДая из которых содержит ссылки, указывающие на один и тот же объект в па­
мяти (т.е. "поверхностную копию"). Если вы хотите иметь "детальную копию", когда
состояние внутренних ссылок полностью копируется в новый объект. необходимо
реализовать интерфейс ICloneable (это будет обсуждаться в главе 7).

Исходный код. Проект ValAndRef размещен в подкаталоге, соответствующем главе З.


Глава З. ОСАшrы' языка С# 157

Передача ссыочныыx ТИПОВ поз.начению


Очевидно. ч:те соылочпые ТИПЫ MOryT п~редimать.ся членам типов. как naра­
Merrpbl. Но переда"':lа объекта по CCЪLflК~ "РтЛi,-ч~тсл ОТ его передачи по значению.
Чтобы цонять суть различий, П~ДПОJ1ЩIQ1М. ЧТО У нас есть масс PerS@1] (nepcnнal.
оцределенн:ый следующи;м образом.

class Реузоп

Р(.1Ь] 1 с
st::rlng, fullblame ;
public byte "'og·e -;
pub1i с Реув (Ц1 ( s t ri ng 1\, Ьу te -а)
{
ful1.N.ame = !);
age = а,'

]'
public Per~on() {J
р1щliс 'toid Print1nfo ()
{ COnE:cle .WriteLinet "[O}, !l} года ( дет ) ", 1E"l1llNam!?, оач~ ); !

Теперь создадим :метод. который позволяет БЬL8ЫВающей стороне пересла'ГЬ


тип Perso:n Ш> ЗНач:евию (обр~'Ц1,'е внн:мание на отсутствие модифmtaтaров пара­
метра).

рщxliС static vo:ld SеТJ dА.Ре>IsсщВуVаluе fPer.s .o n Р!


{
/ / J,lз~eиste'1' iI1И 3'1'0 aosp<l.C'l' I р I ?
p.a,ge- = 92;
1/ У.I!идJ'%!I! JIИ В1ШUJIВabI(ЗоВ О'1!орока. ~1IXИе и~е]Jеаии'?
р = l1ew Рех sоол (" }ш..-.:.ки" r 192.) ;

Обратите вI:tи.1vEaliИе на ТО , что метрд SendAPt;!r$otJ.ByValUie () пщтается изме­


I1И1'Ъ получаему'ю ccы.тnty РеТзоn ца lЩВьЩ объект. а ТЗ\РЕе Юlмев:ить некоторые
дalIНble СОСТОЯНИЯ. Дющ:Йт.е провер:им работу этqго метода, ИСI[рЛЬВУЯ следующий
метод Main ( ) .
j ~tatic YDid Main (st.r·ing[] args)
о,

{
I/ Пере~а",а; C~OIblU.1X ~OB по зкаЧ8JfИ1D.
С~)Гjоsоlе.WхitеI,iпе(""'''* Передача объекта Persor. по значению "''''~'');
Pe.r50n frt'!d = nsw Ре.rsо оог!(НФред~, 2};
(0115<01 е . Writ;eLi ne i " Реr-sол до ЗЫЗ'ова -ПQ З liaqоению: ") ;
frеd.РrintIпfа();
SertdAPer.sOnByValue (fred) ;
Сош:юlе. WriteL ion-е ("1'о0О:I1Ю11 JПiJсле вызова .ею значению: "");
fred. P:riTJt Info (! ;

на p~c. 3 ,15 покаааЕ соответствующий ВЫВОД.


....

158 Часть 11. Язык программирования С#

Рис. 3.15. Передача ссылочных типов по значению блокирует соот­


ветствующую ссылку

Как видите, значение возраста (age) изменяется. Кажется, такое поведение при
передаче параметра противоречит самому термину ~по значению", Если вы спо­
собны изменить состояние получаемого объекта Person, что же все-таки копиру­
ется? Ответ здесь следующий: в объект вызьmающей стороны копируется ССЬика.
Поэтому. поскольку метод SелdАРеrsопВуVаluе () и объект вызывающей стороны
указывают на один и тот же объект, можно изменить состояние данных объекта.
Что здесь невозм.ож·но, так это изменить саму ссыJшy так. чтобы она указывала на
другой объект (зто напоминает ситуацию с постоянными указателями в С++).

Передача ссылочных типов по ссылке


Теперь предположим. что у нас есть метод SendAPersonByReference (). кото­
рый передает ссылочный тип по ссылке (обратите внимание на то, что здесь при­
сугствует модификатор параметра ref).
public static void SendAPersonByReference (ref Person р)
(
1/ Изменение нехо'1'ОРЫХ даlUnJX 'р',
р. age = 122:

11 Теперь 'р' ухазwвае'1' на новый об'ЬеХ'1' В динамической ПВИR'1'и!


р = пеМ Реrsоп("Никки", 222);

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


гибкость в управлении входными параметрами. Вызывающая сторона не только
может изменить состояние объекта, н:о и переопределить ссылку так, чтобы она
указывала на новый тип Person. Рассмотрите следующий вариант.
static void Main(string[] args)
(
/1 Передача ссылочиwx '1'ИПов по сcwnхе.
Console.WriteLine("\n*** Передача объекта Person по ссылке ***");
Ретзоп mel = new Person ("Мэл" , 23):
Console.WriteLine("Persol1 до вызова по ссылке:");
mel.PrintInfo() ;
SendAPersonByReference(ref mel):
Солsоlе. Wri teLine ("Person после вызова по ссылке:") ;
mel. Printlnfo () ;
Гпава З . ОСНОВЫI!ЗЫК8' С# 159
Из рис, 3,] 6 ВИДцо. "ЧТ(j), ТJШ С и;менем Мзл ВQзвращаетс:я: после BJ>JaO,El:l lШR тип С
именем 'НИККI1.

РиС.3.16. ПереДВ"iа ОCblЛОЧНЫi( типов, тю ССЫЛКЕ! позволяет пере­


направить ССЫ11Ху

ЗОлотым .дра-вилом при :передаче ccьцlo'т;EIых ТИЦОВ' по ссылке являетtя cil1eцy­


JOщее.

• Если ССI:!IЛОЧНЫЙ тип передается по ссылке. ТО вызъшающан сторона моmет


И-З)iе~n' нетол::ЬКо состояние данных соответС'rвующего объекта. но сам
об~юn CCblJU<iU-

J(CJtOAНIdQ \СОД. T'Ipoen RеfТуреVа!ТуреРагаms размещен I;J подката)1оге, ООО~ТСТ&уЮщвм главе З,

Типы, характеризуемые Зl:lачениями, и ссылочные типы;


заключительные замечаниS1
Ч7'Обы зав~рщить обс.ужде,ние данной темы. ,изучите информaдkЮ 1'абл, 3.8,. в
~оТороЙ nPlffiОДИТсЯ краТRЩ[ сводка оcшuшыx. 'отличий МеждУ типами:. харaJt'Гери-­
зуемьц.щ з~аqением. ~ ссылоЧНЫми типамИ.

1аБJ1КЦЗ 3.8. Сравнение ntПОJ;l, характеризуеМЫХ:il~Щ(lе~lием" и СОbl110ЧНЫХ ТИПО8

Тиn~ харanеризуемыJi
BOnPQc
ЗН8че",МtЩ

Где разм~щщщ;я тип? .В Oi~Ke Вynравl1Я8МОl1 J!ИflаМlll'lе­


'СКОЙ памяти

Как ГlреДGТ81ЩIЩТС9 л~ременнзя? в виде m.жальной kопии' В виде ССЫЛКJ.1 на место в


памяти, заfl~tDе соответст.ау­
ЮЩИМ эк3.еМГlЛярам

Чiто RВJ1яеn:я базовЫм типом? QкаЗ~lвается npОИЗВОДНblМ Может получэ.Т~СЯ иэлю­


от S'y·stem. V,э.luеТуре бqго типа (Iфоме Sуэtеm.
va1 -u етуреJ, не Я8ЛЯЮЩ6ru·
СЯ ИЗ,олированным (подро.&­
НОСТ\4 в mЩlе 4)

Мржет ли тип бъrrь б~овым ;цтl Нет. Типы. хараt(теризуемые . рР., Если тип .не ИЗОl1I-1РQ.Ван,
Щ)у.гих типов? ЭNаЧ8l'tиями, вcsща lII.ЗоJiи " он' может быть базовым iЦЛi1
раваны и не могут бt:llТЬ РаС­ друrиx ТИП09
ширены

1
-
160 Часть 11 . Язык программирования С#

Окончание табл. 3.8


Тип, характеризуемый
Вопрос Ссылочный ТИП
значением

Каким является поведение, при­ Переменные передаются по Переменные передаются по


нятое по умолчанию при передаче эна'iению (т.е. вызванной ссылке (например. в вызван­
пара метров? функции передается копия ную функцию передается
переменной) адрес переменной)

Может ли тип переопределить Нет. Типы, характеризуемые Да, неявно (подробности в


System.Object.Finalize()? значениями, никогда не раз­ главе 4)
мещаются в динамической
памяти }1 позтому не требуют
финализации

Можно ли определить конструкторы Да. но конструктор, задан­ Безусловноl


ДЛя этого типа? ный по умолчанию. является
зарезервированным (т.е . ,
другие конструкторы обяза­
тельно должны иметь аргу­

менты)

Когда переменные данного типа Когда они Оl<азываютсЯ вне Когда для управляемой дина­
прекращают свое существование? контекста определения мической памяти выполняет­
ся сборка мусора

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


лочные типы могут реализовывать интерфейсы и поддерживать любое число по­
лей, методов. перегруженных операций, констант. свойств и соБЬГГИЙ.

Операции создания объектного образа


и восстановления из объектного образа
ВвидУ ТОГО, ЧТО В .NEТ определяются две главные категории типов (характери­
зуемые значением или ссылкой), может понадобиться представление переменной
одной категории в виде переменной другой категории. В С# предлагается очень
простой механизм. называемый оnераЦllей создш-шя объектного образа (boxing),
позволяющий превратить тип, характеризуемый значением, в ссылочный тип.
Предположим, что вы создали переменную типа sho rt.
11 Создание значеНИJI ~ипа short.
short s = 25;

Если в приложении потребуется конвертировать этот тип значения в ссьmоч-


ный ТИП, ВЫ должны ~упав:овать" это значение так, как показано ниже.

11 "Упаковка" значении в объек~ную ссыпКУ.


object o bjShort = s;
Операцию создания объектного образа можно формадьно определить, КЮ< про­
цесс явного преобразования типа, характеризуемого значением. в соответствую­
щий ссылочный тип с помощью сохранения переменной в Syste m.Object. Когда
значение преобразуется в объектный тип, среда CLR размещает новый объект в
глава 3, ООНОВЫ яэыаa С# 161
дина1\ШЧedroй naмя:rй и Еоnиpует аначениесоответствующе:го типа (:в данном слу­
чае это значение 2q).в создaнны'й эвЗeмnnяp. Вам воэвращается ссЫлка на новый
размещеШШIЙ в na.мЛТИ об'Ьеm При иcnam.зова:нйИ тaкoro ПО$Ода у разра6отЧи:на
.N:EТHe 1IоэНИRaет необхоДИМОСТИ ИCIJолъзоватъ интерфейСНЪ1е .н.лш:сы.чтобъr Bpe~
меНно 06ращатьс.ll с данными стека как с оБЪектами., раа:мещеННЫмИ 13. динамиче­
СНОМ ПQМЯТJ.L
Обратная операция 'l'оже предУСМОТРена, и шl3"ыветсяя она ВОСё1l1Ш-ЮВленuе..м из
о.бъеЮШ·Ю20 образа {Uhboxing}. Восстановление из объектного обраэа явл.яетсн про~
цессЬм обрз"ГlIOГО преобраэования значенин. (:QдерЖаЩетосп в объе:ктной ССblJПCе. в
значение соответствующего. типа. размещ,аемое в стеке. Операция ВQС'.станОВЛения
иа объе:ктного Qбразз наЧиыается. с npоверки того, ЧТО hпl Дalllihтх., в IЮТОРЫЙ вы­
полняется восстановление. ·эквивалентен типу. который был при:веден:к объекту.
Если это так. :го вьmолннетсн обратное копировaнI1е соответствующегознаЧСНfl:Я
1'J ЛQRaлЬную перем/'шиуто 11 стеке. Например. сЛедУЮщая операЦl1Н ВОССТановл:ени.я
И~ объектного образа буде'! вьmОШ!ена ycneIillf(), 1ЮС}ШЛЬКУ соответствующий тип
Q-ЬjShоrt действительно имее-; ТИП S:flort (операцию преО:бразовJ.ШWI т1-шов в С#
мы рассмотрим подрооно 11 следующей. шаве, а пока ЧТО не слишко:м:беСШ)RоИ:теСЬ
'0 деталях).

/I Об~'Z!~ое преобраЗОВaJ:1Ие СOIoШXИ в соq'IlВетотвущее з·начеии:е short.


shGrt. anotberS'};HЭI:t = (Enort) objSlr,Grt;

Снова Qбратим ваше внимание на то·, что ВQсстано:влenие следует ВЫlIOJIНWГЪ в


соответствующий тип данных. Так, следУЮЩая програ:ммнаи логина восстановле­
ния из объшtт1шrо образа l'енерирует исключение IHvalidCai3tExcept.ion (обсуж­
дение вопросов обработки ис:ключений содержится в главе 6).
/ / HexoppeK!l'HOe ВОf:С'1'зковnеНИIEI ~З Qб'Ъех!t'НО:J;lО образ...
stati{: U"oid Main(stJ;iDg[] a.rgs,)

trj
~
// 'l'иn..s "УПa.lllозхе" ~ Э!I!О НЕ З-nt, а short!
irJ.,t i = ~ int.J obj Shcirt;

oatch (lnvalidC,astExceptHm е}
!
12onsc)le.Wxi tеИnе\"QЙ! \n [О! ", Ii!. TbStrir1g () ) i

Примеры создания объектныx образов


и восстаНовления значений
Вы. Haвepnoe. спросите. ItOrna действительно БЫвает необходимо вручную nЬJ­
ПОЛliЯТЬ преобраэовани:е в. объt".1crный ТИП (или восстановление из объектного об­
раза)? П~ДЪЩУЩИИ прим:ер был иr.КТiliiЧИТелъно иллюстратИRНЫfi>I. поскош.tty n нем
ДЛЯ данных short не было никa:Itои реадьной необходимости привед!ШШlК объ­
ектному ТИiIy (с последующИМ вос€тановлением даЮIЫX из объ~тного образа).
-
162 Часть 11 . Язык программироваНИR С#

Реальность такова. что необходимость вручную npивоДИть данные к объектному


типу возникает очень peДRo -. если возникает вообще. В большинстве случаев
компилятор С# выполняет такие преобразования автоматически . Например. при
передаче типа, характеризуемого значением, методу. предполагающему получение

объектного параметра, автоматически "в фоновом режиме" происходит приведе­


ние к объектному типу.

c lass Program
(
static void Maln(string[] args)

/ / Создание значеНИJl int (тип, характеризуемый значением) .


int mylnt = 99;

/ / myInt передае~ся: методу I преjЦПо.nагаnцeму


/ I по.nучение объекта, поэтому myInt приаОДИ'1'ся:
/ / к об'Ъе!l:'l'НОМУ '1'ИПУ АВ'1'ома'1'Ичесхи.
UseThis Obje c t(mylnt);
Co nsole.ReadLine() ;

stati c v o id UseThis Object(object о)

Console. Wri teLine ("Значением о является: (О}", о);

Автоматическое преобразование в объектный тип происходит и. при рабо ­


те с типами библиотек базовых классов .NET. Например, пространство имен
System.Collecti o n s (формально оно будет обсуждаться в главе 7) определяет
тип класса с именем ArrayList. Подобно большинству других типов коллекций.
ArrayList имеет члены, ПОЗВОЛЯЮIЦИе вставлять, получать и удалять элементы.
public c lass System.Collectlons.ArrayList : object,
Sys t em. Co llection s .IList,
System.Collections.ICollecti o n,
System.Co llection s .IEnumerable,
ICl o neable

public virtual int Add(object value) ;


pиbli c virtual v oid Insert(int inde x, object value);
public virtuai void Remov e(object o bj);
public vir t ual object this [int inde x ] ( get; s e t; }

Как видите. эти члены действуют на типы S ystem.Object. Поскольку все, в


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

static vo id Main( st ring[] ar g s)


Гnвва 3. ОQНОВЫI1Эli/JCВ С# 163
A=ayblst 1tIylnt.s = new AIrayLiBt(J:
myJnts.Add(S8) ;
/ну] !) ts .Add (З. 33) ;
ту] I) t .S . Add I f31se) ;

Но теперь с учеТQМ !3аше.го пониманпя ОChШQЧНЫХ ТИПОВ И типов. хаРflктери­


эуемыхан.аче:J:lИем:, вы можете епро"Ситъ: что же l-m самом де;ле размещае'I'СJI в
ArrayList? (ссы.1Ilщ? Копии ссъшок? Коmш струитур?) Как 11 в сдучае. с рассмо­
тренным выше методом U~еТhis.()Ьjес-t (). ДОЛЖНО быть 8СНО. что кa.жд.ьul 'Из ТИnOiJ
данны:,к System.Int32 перед размещевием.в Ar.rayL.ist в действителыIOСТИПРИВО­
ДИТСЯ R объеJqНОМ), пту. Чтобы восстзнg:виrь элемент ив nша АrrауList.требу­
~СЯ ЦЫll(ЩfШТЬ. uоответствуiomую операцию BOCCTaI-Ювления.

stаtiё v,oid BoxAndUnbo xInts()


1
I/ "VD&IC08~a!' дl"ВIfVX int в Arr.yList.
ArrayList my]rjt.s =' new ,/\,тrауLiэt (') ;
mуIпtS.Аdd(28) ;
rnylnts . Add jЗ .33);
mylnt&.Add(fal.se);

11 Иs:вnеЧeI.Ще пеР:ВОi!О э.nемеи'Ж'& из ArrayLi.st.


inl i .i rs,t1tеш = !iпt.)mуlntз [01.
Соnза J е . Wri tеLiпе ("дepВ'!,>IЪ<1 Э;rJеме.нтvм >Iвлg~·р.с: я [О!", f i 1: st.1 tero) ;

Беэ сомнения. операции upив€дel:IШI .к объектному nmy и восстановления из


объеК'ТI-Iогообраза требyкtt времени И, ёсли Э'fl) операции использовать без огра­
Щ)Чt'юЩ, это может ЮIИЯТЬ на llpoи;mодительность npйложения. Но t использова­
нием ТaR(IГО подхода ЯЕТ.вы можете с:имметрИЧI-to ра(50тать с nmами.. }щрanерщ­
~емыми значенИем, и со сcыл.чвьrми тиnам.-и.

Замечание. !3 С# 2' Р flотери ГlРОИ~ВОДИ1ельн~с"и из-за пр~едения " с€)ылочному' типу И аосCi.тэ­
нов:tlения !ltз объектного 06раза Можно нивелvrроооть ПуТем испопъзоваНИII 0606щеN",Й (gene-
rics), к,оторые бvдут pacqMorpeHbI в главе 10.

Восстановление из объектного образа


ДЛЯ пользовательских типов

Котда методУ. llредrшл.arающему получение ЭR3емnлнров Sys tem.. Object. пере­


.даются llолъэоваТf::J"1Ъс:ltae cTpyRтypы или перечни. ТО>il:е. происходит их приведеlЦ1:ё

R оБЪектному типу. Oдnaкo после получения В1({)дноrо оораметра БЫЗВанным мето.­


.дом IIЫ не ~ожет€ ПОЛУТ;ШТЪ ДОC"ry11 J\ каким бы то НИ было "щ:енам CTPYI<Тypbl fИJm
перечня), п6Rа не ВЫIIол::в.m:е операциlO ВОССТaIlOвлеНШI из объеКТ'НQГО образа для
даmшrо типа. Вспомним cтpy1cJypy MyPoint. определенную 11 этой Fшше выше .

$truct MyPb:LFlt
{
public iл .t х, у:
-
164 Часть 11. Язык программирования С#

Предположим. что вы посылаете переменную MyPoint новому методу с именем


UseBoxedМyPoint () .
stat1c void Main(string(] args)
{

MyPoint р;
р.Х = 10;
р.у = 20;

UseBoxedМyPoint(p);

При попытке получить доступ R полю данных MyPoint возникнет ошибка ком­
пиляции. поскольку метод предполагает. что вы действуете на строго типизован­
ный System.Object.
static void UseBoxedMyPoint(object о)
{
// ОШибха! System.Object не имеет чnеНQв-перемевных
// с именами 'х' и 'у'.
Console.WriteLine("(OI, (11", О.Х, о.у);

Чтобы получить доступ к полю данных MyPoint . вы должны сначала восстано­


вить параметр из объектного образа. Сначала можно использовать Iшючевое слово
С# i s для проверки того. что этот параметр на самом деле является переменной
MyPoint. Ключевое слово iз рассматривается в главе 4. здесь мы только предлага­
ем пример ето использования.

static void UseBoxedМyPoint(object о)


{
if (о is MyPoint)
(
MyPoint р = (MyPoint)o;
Console.WriteLine("{O), {1}", р.х, р.у);

I
else
Console.WriteLine("Bbl прислали не MyPoint.");

Исходный код. Проект Boxing размещен в подкаталоге, соответствующем главе 3.

Работа с перечнями .NET


Вдобавок к структурам в .NEТ имеется еще один тип из категории характеризу­
емых значением - это neреч1-tu. При создании программы часто бьmает удобно соз­
дать набор символьных имен для представления некоторых числовых значений.
Например. при создании системы учета оплаты труда работников предприятия
вы предпочтете использовать константы Manager (менеджер). Grunt (рабочий].
Contractor (подрядчик) и "Р (внце-президент) вместо простых числовых значений
Глава З" ОСНОВЫ языка С# 165
{О / 1, 2, 3 f. Именно пО этой причине Е С# поддерживаются IIольэовательcюrе
I1ереЧНИ. Нanpш..tер. вот IIереЧенъ Ептр-Тур.е.

/ / ДOJIЬ$овaorеiiIЬОХИЙ' ПЕ\речень.
enurn ЕтрТуре
j
Manager, /1 = о
Gxunt, 1I :;1
Cont.r", ct. о!' , '} == 2
ур
11 =3

Перечень EлtрТуре определ,нет Че'ГЪ1ре именованные itOHcтmIТbl, соо'тветот:вую­


щие н.онь:реТНЫ:М числовым зна чеШIЯМ. В С# схема нумерации по умолчЭНИ1О пред­
полагает наЧillIО с нулевоrо э:л:еМf."нТа (О) и нумерацию после.цуюших элементОВ ПО
правилам арифметичеСRОЙ IIpоrресс:и--иn + 1. Пр1J необходимости вы имеете ВО3-
МОЖRbC'IЪ изменить такое поведение на более удобное.

/I B.1ЦJIo ИУ*patUDI со "~еВИJ( 102.


enшn ElТlpType

!
Matla:ge'I' = 10~,
Grunt, 11 == 103
COh:,tract6r, /1 == 104
\rlP 11 = 105

Лереtrnи не обязан};l следовать стротому ПОCJIедо:вательноМ:У порЯJU\Y нумераnии


элементов. Ест! (по некоторой причине] вы сочтете разумным создать EтpT~'pe
так, НaR покЭ;эа:ао Ш1Же. 1(ОМПИ:ЛНТОр npим:.ет ЭТО бе,а возражений.

1I эnемвиlJ!'ы перечs,я se обяз;uш спедОИ&!l'ЬВ сorpОI'OЙ noc.n~OBa'1'em.HOClJ!'H!


елum Етр'Туре
j
МаШН]$Х = 1 О,
Grнпt = 1,
COHtrac:tor = 100,
VP = 9

Тип, используемый для .каждоrо элемента в переЧ}iе. по УМОЛ"IaR1iЮ отобража­


etся в Буs t~m. It:i't32. "ГЩtое повеД~ние при ftеобхоДИМОС'ТИ тоже можн:о измениIЬ.
Например. если вы Хотите. чтобы со();тветСТlJyющее хранимое эначеЦие Ernp'J':ype
было byte. а не i JiJt.• вЫ дoJ1жuы1 налиеать следующее.

11 ТеаеРЬ EпlpТуре ОIRобра,,.е'l'CJI, а byte.


епат ErnрТур& , byte
{
MaJ1ager = :1 (1 I
Grutlt ~ 1,
Сопt.'!:а'Gtбr = 100,
VI'= 9
)
-
166 4аеть 11. Язык программирования С#

Замечание. Перечни в С# могут определяться в унифицированной форме для любого из числовых


типов (byt e , sbyte , s h o rt, ushort, int, uint, l o ng или ulong) . Это может быть по­
лезно при создании программ для устройств с малыми объемами памяти, таких как КПК или
сотовые телефоны, совместимые с .NEт.

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


вместо так называемых "магических чисел". Предположим, что у вас есть класс,
определяющий статическую ФУНКЦИЮ с единственным параметром ЕmрТуре.

stat ic v o id A s kForB o nus(EmpТype е)


{
switch(e)
{
сазе EmpТype.Contractor:
Console.WriteLine("BaM заплатили достаточн о •.. ");
break;
сазе ЕшрТуре.Gruпt:
Co nsole.W r iteLine("Bbl должны кирпичи укладывать ... ");
bceaki
c ase EmpType.Мanaqer:
С оп s о l е.Writ е Liпе("Лучше ска жите, чт о там с о пци о нами!");
breaki
сазе EmpТype.VP:
С о пsоlе.WritеLiпе("ХОРОШО, сэр''');
bre ak;
default: break;

Этот метод можно вызвать ТаЕ .

static v o id Main(string[ ) arg s )


{
/1 Создание типа contractor.
ЕmрТ ур е fred;
fred = EmpType.Contractor;
AskForBonus (fred);

Замечание. ПРi1 ссылке на значение перечня всегда следует добавлять префикс имени перечня
(например, использовать ЕmрТуре . Grl.lnt, а не просто Grunt).

Базовый класс System.Enum


Особенностью перечней .NEТ является то, что все они неявно получаются из
System.Enu m. Этот базовый класс определяет ряд методов . которые позволяют
опросить и трансформировать перечень. В табл. 3.9 описаны некоторые из таких
методов. и все они являются статическими.
ГnВBa 3. ос/щвы ~ЬШI С# 167
Табл.ща 3.,9. PSjA стаТИ'Iеских 4Лe!-I'ЬВ System .Eflum

Чnем Оп"'самме

Fo.rmal (:), Преобраэует эначен.ие д.аннего Пfпа пере-щя в эквивалентНое ctp.()j(O-


Вое. ПРЕЩставлеНfl~IJСООТВе'ГСТВИИ с указанным ФQрматом

GеtNаще() Возвращает ИМ~ (И1lи МВООИ8 ИМ81'1) дЛЯ константы с yкaМJ,HHЫM значе"
'GHNames' () ~ием

'1;e.tUnde·Йу il)gType ,( ) В'озВ]Защэет n1пдзнных, I-fдп(!)льзуемый Д11Я хранения значений' дlmHOгo


пере'lНЯ

G"tVaJ иеЕ ,() 8QЗвращает массив ЭН.ClчениЙ КОКСТElН1 данноФ перечня

I.$Def ir1e'd ( ) Возарщдает прlIIЗ'NВК существовакl'Il'I в ,lJЩIНQМ Гlepe 1 1He кi:J1:ICТW1ТbI с УII:Э­
заННbiМ 3НВ\l6Нием

Преобразуе'т cтpokOBoe представnвние имен или чИСflDВьр\ ЗНаче~lIйЙ


ОДНОИ ИЛИ 1-I6СКОlll:КИХ IЮнстзН-Г перечня в эквиваilентtfый объект перечня

Статический метод Е·nшц.Fоrmаt () МОЯСН0 Jl!t::IIОЛЪ3(ПЩТЪ С флагами форма­


'l1ИРОВaJ-ШЯ. :КOTOpы.~ расуматривlYЦIС;Ь ~~ цри обсуждении S'УS'!1., еm.Соп.s:оlе.
Например. Mm'КHO из.sдечь· строку с именем (уIЩЩlВ G). шестнщщатеричное (Х) или
<ЩС)lовае значение (Ь. Fи т.д.).
В .system.Eтi.um ,$Же определяется статичесК1'lЙ метод GetVBloes О. Эт{')т метод
возnращает экэе:мrI.i1др Sy~tem,Array (мы I1Jбсуди;м ~TOT оБЪСЕТ немногоnозже). в
котором liЮtщдrй элемент соответ<:т:вует царе "имн-эначение" Данного переЧНR. Аля
nримера рассмотрите следующий фрагме;нт прDграм:мнIJrО :кода.

5latic щ)l ·d Main{stIiag [) G·rgs)

/ / Пе'\fl1оп. юtфориации .Ц.ttR пер8!1ИR hpТypit.


Array obj = Егш'ffi . ·G et\i'alues (typeof (EtnРТУРЕ!) ) :
C'o.nsol е. Wti teL·i!lE: ("Б ЭТОМ f:iерёчне [О) членов.", o.bj' .l,ength) ;
foreach {.Етртуре е in: ш'j)

I
с'()!1;$ыl.writе(''с'1'рокц r и;менем~ {О ' },'·, e . To5tl-ing(» ,;
СGnэ:оl?WIitе("int: (IDJ), "1
Елum.Fожme.tltуре:()f(EmрТуре), е! "D"));
COQ5o.l.e . W:c i te ( "hex ~ ( ! О f j \ц" ,
Е'nuш •.Fо:r::шat.{tуреоf(Еmp'Туре), е, "Х" · ));

.1
КfШ вы сами ,1\'fOжете догадатЬСН. этот МОЕ ПРОГРа:'ММНdГО 1юда для nеречня
ЕтрТуре Пе'Ч.атцет пары ~11JV1Я-зна~ение" (В десятичном и шеGТНадцатеричном фор~
Ma-re).
Теперь и"Сс.rrедУем СВОЙСТВQ IзDеfin,еd. Это свойство IImшолnет вьrnсНить. ЯВ­
ля:ется ли да:ещa.FI строка "l,леl-ЮМ данного переч:ня. llредшшожим, чтФ I-IYЖНQ ВЫ~
яс}шть. ff.IЩнеТС.ЗJШ ЭI:Iа'[Jение g·alesPer:,sDfi (продавец) частью перечня EropType.
Д1гя этого вы доmItfllil по~лать укаванвой фy1nщии информацию о 'тиnе перечня и
crpol\Y. цоторую требуе'fCJl .Р pOBep:mъ (информац;пю о. типе можно. получить с по­
мощью оцерацщr t:ypeof, 1j:оторая подробно рассматривается в r:naвe 12}.

L
-
168 Часть 11 . Язык программирования С#

static v o id Main(string(] args)

// Ес'1'Ь nк значение SalesPerson в ЕшрТуре?


if (ЕпшТL. IsDefined (type o f (ЕтрТуре), "SalesPerson"))
Сопsоlе.WritеLiпе("Да, у нас есть продавцы.");
else
Console. Wr i teLine ("Нет, мы работаем без прибыли ... ") ;

с помощью статического метода Enum.Parse () можно генерировать значения


перечня. соответствующие заданному строковому литералу. Поскольку Parse ()
возвращает общий System.Object. нужно преобразовать возвращаемое значение
в нужный тип.

// Печа'1'ае'1' "Sally is а М&naqer" .


ЕтрТуре sall у = (ЕmрТуре) Епиm. Parse (typeof (ЕтрТуре), "Manager");
Console.WriteLine("Sal1y is а (О}", sally.TOString());

и последнее. но не менее важное замечание: перечни в С# поддерживают раз­


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

ниями . например:

stati c void Main(string[] args)

// !СакаJl кз З'1'ИХ переиенных ЕшрТуре


// _ее'1' боnьшее чкcnоное значение?
ЕmрТуре Joe = EmpType.VP;
ЕтрТуре Fran = EmpType.Grunt;
i f (Joe < Fran)
Сопsоlе.WritеLiпе("3начение Джо меньше значения Фрэн.");
else
Сопsоlе.WritеLiпе("Значение Фрэн меньше значения Джо.");

Исходный код. Проект Enums размещен в подкаталоге , соответствующем главе 3.

Мастер-класс: System.Object
Совет. СледУЮЩИЙ обзор System.Object предполагает, что вы знакомы с понятиям и виртуаль­
ного метода и переопределения методов. Если мир ООП ДЛЯ вас является новым, вы можете
вернуться k. этому разделу после изучения материала главы 4.

в .NEТ каждый тип в конечном итоге оказывается производным от общего базо­


вого класса System.Object. Класс Object определяет общий набор членов, поддер­
живаемых каждым типом во вселенной .NEт. При создании класса. ДЛЯ которого не
указан явно базовый класс. вы цеящю получаете этот класс из System.Object.
Глав~ з . OCHOeJ~ gзы~а c~169

/I 1Iе_ное пощчеиие 1UIaCca из System. Obj_ct.


с1"ЭБ f.iеl10Сlэ.ss
{, . -}
Если I!1Ц же.тщете уточнить свои нам:ерен:ин. ·операция: CfI. оБОЗВ:ачаемая двоето-
чие~ (:). поэволяет явно JЩlзать базовый ЮIaС{1 :mna (rнmример. System. Obj ect).
11 в обоих CJ'Jуч&а х.пасс авио поnучается: из ЗуS teuC ОЬ] ect .
;:1<'155 ShapaInfo $уstеш. _ОЬjе~t
{ ... }

cla~ 13 St!apelnfo ~ obj ect.


{ ... }
' Тип 8уstепt.ОЬjесt Ol1.рс;щел;нr;:т дабор членов :эв:эeмnлнpa:и: членов тmacca (ста­
тическщ членов}. 3aмeтlD(, ЧтО некоторые из членов экземпляра объявляютсн с
иЩ!ользоианием ключевО1'О сщща v;i r tual и .поЭтому мnгyт nереопреёk:nяrtu:;cя. по­
рощцаемым классом.

11 1tпасс, sаllИllапф!й B&Jt'8ЫC1II)'1D позиЦИю:в . nт :


/ / System.opjeat
паmеsрасэ System
(
public class Object
(
рцЬ1iс БЬjесt () ;
pUblic vi:Z:'щаl Вооlем Щ'qu.а~s (Object obj) i
public vЦtual. гntЗ2 GetЛаshСоdе() ;
publ ic' Туре .G,e tType () ,.
public virtual St:rlng TQSt.ting (') ;
prdt'e :cted virtua'l 170id Fi n aliz,e () ;
prCltected Obj ect МenФеrwi$е~lОIiе () ;
public s'tatic Ьс:юl ЕщuаJs (object objA, оЬjесt, оЬj:Б);
pUblic static ЬоЫ ReferenceEquaJ.$ (cbje:etQbjA" object objB);
}

в табл. 3 . 1Q предлагаются описания функциональных В/!)ЗМОЖiiостей методов


8l(3еМJJ.!lЯра Д71Я указаннoroобъен:та.

'rабmща 3.10. Наиболее важные членВI Sys tero .Obj ect


Метод экзеМIIJUlра
Описание
kJJacca ObJect
Bquals (1 Пр умолчанию вазвращаетtru€ (klС1Игlа), кщца сравниваемые эдемен­
ты .ссылаются на ОЩ1Н м тот же эл'эмент в памяrи. Поэтому иr:пользувт­
СА ДЛl'I cpaSHeHIIIII об~т-ных оcыl01c,' а I'te состояниЙоОъек:тов. ОБЬ/чно
nереоп~еделяетсятаlC'l 'побы ЗIiа.чеНие trl.ie ttО.э~ращалось ТOC:Д~I
KOrдa оравниваемые объекn.lимеют адинаковыe значения 8Hyтpelfflero
состояния (т.е. одинаковую семантику значений). При переanрвделенltИ
Есчuаl;; () следует также, переоnpедSIlИТЬ GetJlashCode ()
80З&ращает цeno~ значенйе~ иДентифицирующее объеu в псщS!ти .
ЕсЛli1 вы собlltраетв.оь разместить оnpедеnяемые вами' ТИf11'i1 в Т&:Iпе
Sуstею.Соlleсtiоns. Elashta151 е,. рекОМендуется Т1ереоnредели'l'Ь
эа.о.аi'!НУЮ по УМQJlча~IИlО реализациlb этого члена

...
170 Часть 11. Язык программирования С#

Окончание табл. З.10

Метод экзеМПЛllра
Описание
клаоса Object

Equals() По умолчанию возвращает true (истина), когда сравниваемые элемен­


ты ссылаются на один и тот же элемент в памяти. Поэтому использует­
ся для сравне~IИЯ объектных ссылок, а не состояний объектов. Обычно
переопределяется так, чтобы значе~lие true возвращалось тогда,
когда сравниваемые объекты имеют одинаковые значения внутреннего
состояния (Т. е. одинаковую семантику значений). При переопределении
Equals () следует также переопределить GetHashCode ()
GetHashCode () Возвращает целое значение, иде~lтифицирующее объект в памяти.
Если вы собираетесь разместить определяемые вами типы в типе
System.Collections. Hashtable, рекомеl1дуется переопределить
заданную по умолчанию реализацию этого члена

GetType () Возвращает объект System. Туре, полностью описывающий данный


элемент. Это АТТ\·метоД (RunTime Туре Identification - идентификация
типа в среде выполнения), доступный для всех объектов (соответству­
ющие вопросы обсуждаются в главе 12)
ToSt.ring () Возвращает строковое представление данного объекта в формате
пр ос траНСТВ0 Имен.имяТипа (т.е . полное, или абсолютное имя) .
Если тип определен не в рамках пространства имен, возвращается
только имяТипа . Этот метод может переопределяться подклассом и
возвращать не абсолютное имя, а строку пар имен и значений, пред­
ставляющих BHyтpe~IHee состояние объекта

Finalize () Этот защищенный метод (если ОН переопределен) вызывается средой


выполнения ,NEТ; когда объект удаляется из динамической памяти.
Соответствующий процесс сборки мусора рассматривается в главе 5
МеmЬеrwisеСlопе () Защищенный метод, возвращающий новый объект, который является
"почленной" копией данного объекта. Если объект содержит ссылки на
другие объекты, то копируются ссылки на соответствующие типы (т.е.
выполняется поверхностное копирование). Если объект содержит типы,
характеризуемые значениями, получаются полные копии значений

Поведение System.Object, заданное по умолчанию


Чтобы продемонстрировать некоторые особенности принятого по умолчанию
поведения базового класса System.Object. рассмотрим класс Person (персона),
определенный в пользовательском пространстве имен ObjectMethods.
11 J(.nючевое слово 'патезрасе' обсуждае'l'Сfl в Itонце Э'l'ОЙ I!Л&В~.
паmеsрасе ObjectMethods
{
class Person

public Person(string fname, string lname , string З, byte а)


(
firstName = fname;
lastName = lname;
SSN s;
age = а:
Гл.аsа З. ОСНО.ВЫ !lЗЫkа С# 171
рм1 ic PerSC[J)! ) I I

/1 .пероовa..пыote ~ёtJiКi1e (д!!flJlliП! СОС'1'ОRИИII') •


pllbl ic ,s 'lr iлq fi r st Ni:П[lе;
public s1.riiJg lastNarne;
рцЫ:!, с s t ring SSN;
P'l.1DblC .bytE ag€;

Теrщръ ИСIД)щ,зуем тип t>e'J: 50Л.в рамках метода Mai n ( ) .


stац,с vol.d Маi п :,эtrir!g[! arg.s)
t
Соn,ю1е. ,WritеI,iле("** "' ''''' Работа с :классом ()bj~c;t*"**"\JI"!;

Ре.t::юп fred = new Реrsол ("Фре.д" т IJ'К)1ар,к", 1'111-11-1111", 20) i


С-опsоlе. Writ'e Line (.1_> fred. ToS:triJ!:C;p {D J ", fred. Tostring О ) ;
Сош;оls .Wlri teblne (11,_> f:ted. GetHashCode: IO}" т fr'ed . Ge'tHa.sl'ICode (.) } ;
Console .WriteLi:ne ("-> базовый масс длR 'fred': (О) ",
fred.GetTypeO .ВаsеТуре);

11 СО\9давие ;ЦОПО.nвитe.льR1tlX CC:WnOIQ .на 1 fred' .


Ре! $Оn р2 = f r 'ed;
O'bje-~t о = р2;

11 Y~&SJil8i!1JD'1' .пи lIсе 3 Э, КЗeJIПJIRp& Jla О;J(ЙН об'bl!lХТ :в I1ёUaI'mf?


if (0. Eqaa:ls (fred) Н р2 .:Eqt1al s (, о) )
Со!) 5<;>1 е. Wri teLlne (" fred, р2 и: .о се;ылаютсн на OД~H .Об'1;е,~Т'! "")' ;
Солsо1е.RеаdЫnе(};

Na рис. 3.17 покasaн вариаит BЬJВOдa. полученного при TeLTOBCIМ запуске :upo-
граМмы.

Рис. '3.11. РеализаЦИя члеНОв Sys,t em. ОЬ j е с !:', заданная по УМОJ{qа~1ИJO

'Обратите ВIiиыatmе на ТО, что SМЮllЩК I10 умолчанию реализа'ф!я ToS'tring ()


ПРОСТО возвращает полноеи.~'ТИlIа (нэцример, в виде лр.оtтраRСТВОJlJ.М61-I.имяТипа).
Меroд GetType О возвращает объект System.Type. который о-пределяет cDой­
ства В:аэ'еТуре (как вы .можете ДQГЗ.lЩТРСЯ сами. оно идентифицирует полное J(МЯ
базового ЮIасса: дацноro 'ГИШ:l).
Теперь раССМОТРт! ЛРОГРaММI-IЫЙ ПОД, испо:льзyюiЦИЙ метод Equals П. Здесь в
управляемой ДU1:Iа.'fo,Ш'qеСRОЙ пам1JТИ ра~щаетси новЫЙ объект J?€rso.n. и cCblJlНa
на этот объект зanом:инаетс,n в ССIo1ЛО<;IНР:ir перемеimОЙ fХ'Бd. Пере....rенн:ая р2 тоже
-
172 Часть 11. Язык программирования С#

имеет тип Person. однако здесь не создается новый экземпляр класса Person. а
присваивается fred переменной р2. Таким образом. и fred, и р2, а также пере­
менная о (типа object. которая была добавлена для полноты картины) указывают
на один и тот же объект в памяти. По этой причине тест на тождественность будет
успеIIIны •.

Переопределение элементов
System.Object, заданных по умолчанию
Хотя заданное по умолчанию поведение System.Object может оказаться вполне
приемлемым в большинстве случаев. вполне обычным для создаваемых вами типов
будет переопределение некоторых из унаследованных методов. В главе 4 предлага­
ется подробный анализ возможностей ООП в рамках С#. но, по сути, nEреоnpеделе­
ние - это изменение поведения наследуемого виртуального члена в npоизвоДНом

классе. Как вы только что убедились. System.Object определяет ряд виртуальных


методов (например. ToString () и Equals ()). задающих предусмотренную реализа­
ЦИЮ. Чтобы иметь друтую реализацию этих виртуальных членов для npоизводного
типа, вы должны использовать юпочевое слово С# override (букв. подменятъ).

Переопределение System.Object. ToString()


Переопределение метода ToString () дает возможность получить "снимQ'l~" теку­
щето состояния объекта. Это может оказаться полезным в процесс е отладки. Для
примерадавайте переоnpеделим System.Object.ToString() так, чтобы возвраща­
лось текстовое представление СОСТОяния объеJ<та (обратите внимание на то, что
здесь используется новое пространство имен System,'Text).
11 Нужно СОCnil.'1'ься: на System. Text ДЛЯ: доступа к StrinqBuilder.
using System;
using System.Text;
class Person

11 ПереоnpедenениеSystem.Object.ToString() .
Pllblic override string ToString ()
(
StringBuilder sb = new StringBuilder();
sb.AppendFormat(" [FirstName={O}; ", this.firstName);
зЬ. AppendForma t (" Las tl'{ame= { О } ; ", this .las tName) ;
sb.AppendFormat(" SSN={O);", this.SSN);
sb.AppendForrnat(" Age=jO)]", thi,s.age);
retufn Sb.ToString();

То, как вы форматируете строку, возвращающуюся из Sу s t е m. О Ь j ес t .


ToString (), не очень важно. В данном примере пары имен и значений помещены
в квадратные скобки и разделены ТОЧl\ами с запятой (этот формат используется в
библиотеках базовых классов .NEТ).
Глава :). ОСН.ФВЫ язьrка С# 173
в этом nPИМl1Jе ИСП0JIb3уется новый тип Slys.tеm.'!екt:.strinч)3u,i1dеr. Jtщ'Qрь1Й
будет подробно ОПИСa1i . ПОЭ-Же. Эдесь c.т:reдyeт толыtр ПОдчepRНy'P>. ~ТQ Str;iпg;6uildеr
обеспечивает более эффективную альтернативу :конкатенации СТРOI( 1'1 С#.

Перео'лределение System. ObJect. Equals()


Давайте переопредеЛЙ1\.1 и поведе·вие S'i'stem.Obj ec.t ,Equals (), чтобы ЦМe-FЬ
воамОЖНОСТЬ работlПЪ с ceMaнmwcoй. QCН08ЩiНOй на .знпч.енuяx. На:п~. что по

I умолчанию Equa.lS () возвращает


указываю'! на один И тот )ке объект
:tru:e (истина}. коrда обе сравЩIВаf;J':tI.f.!Iес(;ЪD'IЮI:
11 дmlзмичеC'RОЙ пщ.tити. Одн.цно чаСто быва­
ет нужно не. то, чтоб.l>I;:ще ССЫЛКИ уваэывали :на один объект в .J;faм~. а чтобыI
два о(!iъекта..имели OД1>UtaJCOBble сост\i)ЯliИЯ (В случае Рех БОn ЭТО Qз~ачает равенство
значеImЙ пате, 53}'] и аче).

риыi: overr1d€ bool Ечtlаls{оЬjесt о)


J
/ / УбеjфDlСR r '1'1.10 IIWЗwaа:ацая: C'1l0pc»l. ~оcшn.е'1'
I/ ~ейсшви'1'anъJWЙ оkеюr: Person.
i f (о :! = n:ull && о is person)

I
/I 'Теперъ npollep_, Ч'l'О ~&JПWЙ 'o&J;ex'1' P'erson
/I k 'l'е1l:УЩИЙ оl$иJW (thia) teeCY!1l
I I /qAЮlа-.сО!l~ ~фо~.

I Pers.o'n temp =
if (temp. firstName ==
(РеrSQЛ)С);

thiэ .• firstName &&

I temp.la·stName == th:i5.1astNa:me· &.&


ternp.SSN == this.SSN &&
temp. age == thi s .a,ge)
retUIIJ t.J:ue;

retuI n fаlзе; / / Не одиааКGa)l.1D'

Эдесь с помощью ключевого слова is язы1-ta С'# .ВЩ сначала npoверяете, что цы­
зъtвaюiЦая CТOPOI'Ia. действи:телъв:о перецает методу Equals. () объект :Per so:n. ПQсле
атоl."О нужно сравнить ЗШiЧ'еНИе поступающего napaMerpaco значениями що.де9
,цанных текущего объекта (Dбратите Dнnмaние на иorюцьзование ЮIЮчевоrо с.лР.Бil
this. которое ссылается на текyщJIЙ объект).
Пр.ОТQТJ-Ш Sy st е tn.. Obj ее"!: . Ечиа 1 g () npeдnoдaгaeт ll.Oлучекие единственно­
го аргумеtlта ТИШl object . nQЭТОМУ вы доЛжны вьшалиитъ щшый ВЫЗОВ МieTOД~
Еquэ.ls () . 'iТобы ПOЛJ"Ч}fТЬ доступ 1\ членам тнпа I.'ersot:\. ЕС,lЦifэначения пате, S5N
и age двух. объектов будут иденти~ы. вhi имеете даа объек:га: с одина:кОВЫМИ' дан­
ными СОС.!fOЯRин. I1OЭ'roму воз:вратится true ()IC'IШЩ). Если :ка:к.ие-то д~e БУду'f
раЭJrИ'Чаться. вы получите false (ложь).
Пбреоnpеделив System. Object .ToString () ддя данного класса. вы получает~
QЧem. простую возможность переоnределенmtSуst~m ..abj E'ct .'Eq'llals () . ЕCJЩ :ЦО3-
вращаеМ'Ое й3ТоЗtr:iл'g () значение учитывает все члены тепущerо WIJ3.cea (;и дан­
ные базовых кnaccoв). то метод .Equals {) может nPO~TO сравнить эначeцщJ соот­
ветСТВУЮIЦЯX стро:ковых ТИПОВ.
174 Чаоть 11. Язык программирования С#

public override bool Equals(object о)


{
if (о != null && о is Person)

Person temp = (Person)o:


if (this.ToStrinq() == o.ToString(»
return true:
else
return false:

return false:

Теперь предположим, что у нас есть тип Car (автомобиль). экземпляр которого
мы ПОIIЫтаемся передать методу Person .Equals ().
/I A!lТОlllобили ~ это не moди!
Car с = new Car();
Person р = new Person();
p.Equals (с);

Из-за проверки в среде вьшолнения на "истинность" объекта Person (с помо­


щью оператора is) метод Equals () возвратит false. Теперь рассмотрим следую­
щий вызов.

// Ой!
Person р = new Person() i
p.Equals (mJll):

Это тоже не представляет опасности, поскольку наша проверка предусматрива­


е'!' возможность поступ.пения пустой ссьшки.

Переопределение System. Object. GetHashCodeO


Если l{ласс переопределяет метод Equals (), следует переопределить и метод
System.Object.GetHashCode (). Не сделав этого, вы получите предупреждение
компилятора. Роль GetHashCode () - возвратить числовое значение, которое :иден­
тифицирует объект в зависимости от его состояния. И если у вас есть два объеItта
Person. имеющие идентичные значения пате, SSN и age, то вы должны получить
для них одинаковый хеш-код.
Вообще говоря, пере определение этого метода может понадобиться только тог­
да, когда вы собираетесь сохранить пользовательский тип в коллекции. использу­
ющей хеш-коды. например, в System.Collections.Hashtable. В фоновом режиме
тип Hashtable вызывает Equals () и GetHashCode () содержащихся в нем типов,
чтобы определить правильность объекта. возвращаемого вызывающей стороне.
ПосItольку SysteПI.Object не имеет информации о данных состояния для произво­
дных типов, вы должны переопределить GetHashCode () для всех типов, которые
вы собираетесь хранить в Hashtable.
Есть много алгоритмов. которые можно использовать ДЛЯ создания хеШ-кода.
I{aк "изощренных". так и достаточно "простых". Еще раз подчеркнем, что значение
хеш-кода объеI<та зависит от СОСТОЯНИЯ этого объекта. l\ласс Sуstеш.Striпg име­
ет довольно солидную реализацию Getl-lаshСоdе ( ). основанную на значении сим-
ГЛВjJ8 З . Оснрвы ЯЗЫJfа С# 175
вDлъных да.нных. Поэтому. если .можно наЙти cTp0КDBoe поле , КОТО'рое будет jI-ПJ ·
палъны1M ДЛЯ :всех рассМатриваемых объе.ктов (например> поле SSN длн объе1tТов
perso:n). то можно вызвать Ge.t!1asb'CQde () для стро:к"вого преДС::rnI!ленИи такогО
ЛОШL

J !вo.sараза.ае.'l' хеш.-·XQn росвозе SSN.


pu.bliq ove:rride iot GetHashCode()
j
ret.urn SSN[.GetHashCQde ();

Если вы не сможете указать nодходmциii элемент дa1JЛЫХ. но переопределите


ToStriIl'g (). ТО Мf)ЖНО просто возвратить хеш-кодстрщm, возвращенной: вашей ре­
азшззцие:Йтоs.tring () .
1/ Вопра$е!1' ~81It-JI:O~ ка ОснО8е П()ШоЗОЖ&'l'em.схо'J:'О ToSt:ring () .
Pll\Jlic oyerride iDt Get.НashCoQe ()
t
retu:!'n ToStr:ing {) . Get;HashCode( ) ..
}

Тестирование переопредеnенных чnенов


Теперь можно прове.ритъ обновленный ЮIaСС Person. Добавьте е.ле,цуЮщий про­
грщ.1МНьaf КОД В MttrOA Main() и сравните резуnътат его ВЬШО;lЦl.eНJUf с тем. что по­
lЩЗа:но ~a рис. 3.18.
static vфid Mal:n (strin.g [] .arg~.J
{
11 ВНИМАНИЕ: аши ·о&мIC1nt A~ БЫ!1'Ь идеи'l'И~.
Per$or: рЗ = ne-w P~rson("Fred", ".Jco nes" ., "22.:2-22-2222", 98);
Person р4 ~ new Pe,r.son·(·"Fred", "Jопев"., ~2Z2-2:2-?2'2~"" , 98);
/.1 ToI."дA З1rИ X8IК-XOЦR ,; . С'1'рО1СИ буцу'l' ОдиааХО.ВJВ4И.
Console .·W.'r.l teLine (" -;> ХеЩ'-КQД для р3 = {() J", р3. GetRashCode () .;
C;or,sol е·. W~ i teLine '\ "- > Хеш- ю;;,:о. ;!lnн р4 = f О ) ", р4. GetHa~tJCo.de () ) ;
Со,ns.Qlе"W·ritеLiпеt~-> СТРбка для рЗ = 10}" , p3 .T ~$,tring(»);
Сош~оl е .. 'Wr i teLipe (", -> Стрcmа ддя р4 = ! О)", р4. 1'O'St.r iлq () ) ;
11 Эде~ COC'1'O~ Д~ !S5IТЬ одинаJl:OВUШ.
i f (р .з .E.q;aa-ls )!р4)
'Сопэ.)} е _.WJri teL.i 1те (" -> С ОСТО"1m!Я рЗ И f!J4 оДИнаков!>! \ ") :
else
/)QЛsоlе .:Wri t€Lil;1e (" -> СЬС'ТО'ЯНИЯ рЗ И р4 р.а.з.пичны!") ;

11 ИЗмеlODt "9'е ;ц.J'IR р4.


Gonsole. W.riteLine (" \п-> Изменение age Д..'1>J3 р4 \011) ;
р4. аче = 2;

!I Теперь СОС'1'О"iDIR иеодlЩaJЩJW·; .хеш-ходы и C'1'pOJ.Or б1,fдY'l'· pa'$IIJoIМК.


Соnsоlе.WгitеLiле(,"-> С~рш~а для р] = j.Oj"T р3, ''rоstriщ/());
Ссйзо],е. Wri teLine ("-> СТРб!(а :Ц.iТJt р4 = i О) ", рс4. тоstriпg- () ) ;
C(linSi:JJe. Wri teL.ine ('''-> Кеш-код для рЗ = ! О}", рЗ . GеtЯа·,shеоdе- () ) ;
Сопsоlе.Wг-i.'te.Linе ("-:> Хеш-код для р4 ~ [О}". р4·ЧеtНаЗhСоdе (») i
176 Часть 11. Язык программирования С#

if (рЗ.Еquа1s(р4))
Сопsоlе.Wri~еLiпе("-> Состояния рЗ и р4 од и на к овы!");
e1se
Сопsоlе.WritеLiпе("- > Сос тояния р3 и р4 различны!");

Рис. 3.18. Результаты переопредепения членов Sу stem. Obj е ct

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


в завершение нашето обсуждения базового класса .NEТ. нах:одящегося на вер­
u.mнe иерархии классов, следует отметить , что Sy s tem.Objec t определяет два ста­
тических члена (Ob j e c t.Eq ua l s () и Object.Refer enc eEquals ()). обеспечивающих
проверку на равенство значений и ссылок соответственно . Рассмотрим следующий
программный код.

stati c void Main(string[] a r gs)


(
11 Два обrъеJtта с идентичной хонфигураци8Й.
Pers o n рЗ = n e w Р еrs ол ("Fr ed ", "Jones", " 22 2- 22 - 2222 ", 98);
Pe r son р4 = n ew Per s on ("Fr ed", "Jon e s ", " 222 - 22 - 2222 ", 98);
11 О.цинахоlnl ли СОСТОllНИfI р3 И р4? ИСТИНА!
Conso l e . Write Line ("Од и на ко вы ли с о ст о яни я р3 и р4 : {О} ",
оЬj е сt.Еquаls(рЗ, р4));
/ / ЯвЛRXn'Сfl ли ОНИ одник об'loE!Jt~ОИ В памити? ЛОЖЬ!
Conso le. Wri te Lin e (" Ук азыва ют ли р 3 и р4 н а о ди н о б ъек т: {О) "
object.Reference Eq ualS (p 3 , р4));

Исходный код. Проект ObjectMethods размещен в подкатanоге, соответствующем главе 3,

Типы данных System (и их обозначения в С#)


Вы, наверное, уже догадались. что каждый внутренний тип данных С# - это на
самом деле сокращенное обозначение некотороro типа, определенного в простран­
стве имен Sу stвrп. В табл. 3.11 предлагается список типов данных System, указаны
их диапазоны изменения , соответствующие им псевдонимы С# и информация о
согласованности типа со спецификациями CLS.
,
Глава з . Ос;мевы языка С# 177
Таблица 3.11. 1иnы Sys t e.m и их оБОЗНС1чеfolИЯ в С#

С)6ОЗНll1е· Соrnарован-
нне 11 С# НОСТII с c~e
Тип System ...
д .,.азоН мзменеН... Описание

sby t e Нет sу~t еm.БВуt:е Ф ~ 128 .дo 121 8-битово.е ЧИСЛО


со знаком

b yte да Sys t em.By te от Одо 255 8:-битовое 41о1СnО


без зна ка

sJ10rt да sу st8IП_Iп t lб от - 32768 ДQ · Э2767 16-битовое ~ИС[,Jо


00 знаком

1,Js·hor t He~ Sуstе m.UI n"t l'б от .о до 65535 16-битовое число


без знак~

i nt да S,/s·!'. еro.lл t3'2 ar -21474НЗ648 32~битовое ЧИСЛО


ДО 2147483647 со знака",

uint Нет sу st еm .lJI г.t З 2 от .о ДО 4294967295 З2-битовое ЧIIIСЛО


без· знака

l O;t'I.g Да s у s t.еm.I Тitб4 от-9223372.о36854775808 64-битсвое чием


дО 9223372.о36В547758.о7 со знаком
ul Oi1g . Нет S ув t еm.Ul пt б4 QTOAO Q4,битовое число
18446744,.o73J09551615 без зна~а
ch a r Да S)'Btern. Ch a r от UOOOG Oтnельный 16·
доUffff бl1ТОSЫЙ символ
Unicod&
f.lCfa.t Да SystE;ffi.SinqJ:e от ·1.5x1'.o-41? до 3.4)<. 1(jза 32-БИтовое число
с пnавающим

деОЯТИLI~JЫМ раз-
дели.телем

dOllble Да Sуst.еЛl. О о иЬа е от 5..O~ 1(jIJ24 до 1.71<.1 ОЗ 08 64·'битщюе ЧИСЛО


с плавqющиl'.1

деQЯТI1 ~НЫМ р"3З'


Д6JUIIТелем

bool Да Sузtе m;во.оlеа n t,t"ue J,oIJ1I11 f aI&e Предстаliляет "\о1с-


T~HY Wl~1 110ЖЬ

d e ciroal да. SYS'tern. Deci rnal от 100 до 1028 96-битовое число


со знаком

,St .! :in g да S)':;te m. Stri o,g Qграниченосистемной Представляет


памятью набор СИМВОЛQ8
Unicode
9bj ect Да S}lste.m. Object ЛI0f>ой тип можно ,оохрэ.· Баэов.ыЙ клаСIJ
нить в оБЪЕ!1ffiI0Й пере - асех типов вш
меНflОИ вселенНоЙ .NET

Зам.ечанме . По УМ'ОЛ'lаА ИЮ .деЙствительныЙ чИt:ловвй литерал справа от ·операции ПРИСВЗИВIlI'IИR


I11I1rеРl1реТИР'lется, )(;~ double. Поетому; чтобьт J,1НИЩ1миаирщщть перемеwную тИпе floa t .
йспользуйте оуффИКС f ми F' (fjВПРJdМер. ':' . ЗР ),
-
178 Часть 11 . Язык программироваНИR С#

Интересно отметить, что и примитивные типы данных .NEТ организованы в


иерархии классов. Отношения междУ этими базовыми типами (КЭR и некоторыми
другими типами, с которыми мы познакомимся чуть позже) можно представить
так. как показано на рис. 3.19.
КЭЕ видите. каждый из этих типов, в конечном счете, получается из Syst em.Object.
Ввиду того. что тание тшIы данных, как. например, int являются просто сокращен­
ными обозначениями соответствующего системного ТШIа (в данном случае типа
Sys tem. Int32), следуюIЦИЙ вариант СИНТaRсиса оказывается вполне допустимым.

/1 ПОМИК'l'е! в С, i.nt - это просто сокращение дпя Sуstem.IпtЗ2.


Console.WriteLine(12.GetHashCode()) ;
Сопsоlе.WritеLiпе(12.Еquаls(2З)) ;
Console.WriteLine(12.ToString() );
Console.WriteLine(12); // ToStrinq() вызываеТСR автоматичесхи.
Console.WriteLine(12.GetType() .BaBe~ype);

Туре

- String

- Aц~y

I!юб&й,JМh•.
- " Excepti:on ~t.i~Ът·: h--====:::::::::"~____ .....J

. YAlи~~yp~.. '
Явnяeтся .
aтp~,
ИЛИ~~М;
1 .
но нelJcnacCOU.
. '" .

Мultica;stOelegate
...... .

SByte

Рис. 3.19. Иерархия типов System


ГЛЗ!JЭ 3" OCI'tQltbI ЯЗЫК~ С# 179
к тому же, nО:СКОЛЬ.fl;У в'се типы значений имею.т 1tORcтpYRTOP, 3адa.I'JныЙ п'О·
умо.lt1'i!';llП1l0, можно создавать системные. типы с ПОМО1ЦЬЮ lШ1ОчеВQГО СJ.IOЩ'J П€1lI1. В

p~i,\YJ1bTaTe чего переменноЙ.. IС тому же. будет ПРИСВОeJiO ЗНачение по УМОЛЧ<ЦllIЮ .


Хотя использование .IOIючевОГQ f'.iIOB.a .!i·ew при создании типов ·данных S ув te:fl1 вы-
1ЩIДWГ нееколыю "1ilеyтwюжИм". с:ледylOШ!U! конструкIIйЯ ок<!:зываеff-Я в С# си:втан­
fЩЧ!еш& npавилыrой.

1/ Cnе,ч)']lilЦИe опера!Dli;ipы ЭJCВJIВ&.!"1eJ1"ИЫ.


bQol р1 = nE'M Ь~зJ () ; 11 .ыI = .f"als:e.
Ьо:сй Ь2 = false;

Кстати. заметим. что :можно создаваТJ> сис_теМНЪJе тцnы ДЗНRЫХ. Иf:1l0ЛЬ3yst аб­
солютные имена.

/I c.nе.ч)'XlllVi!l~ опеflа'l'q~ !1'arat8 сеыаи'Ш!'iU!C1IIИ э~вива.пеlWlUiI.


Sys.tem.Bool bl = new S yst.€ H[I.Bocl(); // bl = fals$ ,
Sys.tem.BClol БЬ2 = false;

Эксперименты с числовыми ·тиnами данных


Числовые ТИПЫ .NET поддерживают СВОИСЦЩ И9хVаlщ", 11: M::i. :nValu€.'. сооб­
щающие Иifформаnю() о диапаз~ше цанныJ!:'' Fю'горы" может хр.анить данныИ
тип. ЛрСД1IDЛОШИМ. "{'I'O мы создали нес:колыr.o переменяы.:х 'I'И'llil зу.stеm.1JJf!tlб
(uлsigпеd sbo:rt - короткое целО(" бе.ззнака.) . КIЩ показmю НЮRе.

static void Mail'1 (string!J агgя)


(
Sys teJJl. Olnt16 .!nуП Int 16 = 30"00 0;
Сопsоl€.W.ritеLi.пе("[i1аксимум для Olnt1f.: !О] ", .UInt) ·6 .)4axValue);
СОПS(i)lе.WritеLinе("Ииниму.м .tIдя
UInt.16:JOI' ", Ulлtlб.МiпVа.lue.);
СощJ:оlе.Wr-it..еLirН:J(""Е!н.ачение равна. : {О) ", ПlуU: lntlб,);
С·опs-оl'е.. Ыrit'S'L iпе ("'Я есть: (Ь 1 ", D'lyLJJnt 16. Getтype 1) ) ;

/ / Теперь ;цmr сmo:pащЕ!lЩЯ system. UIn,t16 {,.. е.цт! ushort) .


l1shc-rt mуоtnе rl1Iл t1f, = 12000;
C:OftSole. W'r i te.Line ("Иаю::имУ-м для UInt 16: 1О .) ", ltshort .М4xValue) i
С':!)nsОlе.Vlrit~Lirl~("МИЯ~5М ,фl,>t UlntJ 'б: {О !' '1/ IJsStш:t.Мi.nVaJ.Uе).;
GQllS01e. Wr iteLine{ "ЗНiiJ.чеы:ие равно: {О} "1 m.уОtЬеrщ n Ц'6) ;
С'ойsоlе.WritеLi,п€'('''Я' ~CT·Ь: {О} ", JJlyot+l,e rlJIL1t Lб..Get'l'ype О 1;
СОПБоlе. Re,adLin,e () ;

.адобавок к свойстваМ Mi o\Z.al ue!MaxVa lue системuые тицы ~OГYT опред~.lJЯТЬ


другие nOЛезные члены. Например. тшt ЗУ5tещ. Double ЩЩDОЛЯет ПОдy'Цf'ГЬ :,П-IЗче­
Щ:IЯ ЕРБНОП и lnfioity.
Console. W-r::LtеLl!1е (П -> dQurЙе. БрэilОt1: { О 1 ", dour.,l.e . Epai.lonJ ;
сол:sоlе.!4rl LeLlne ("-> double.Po:sit .i-vеIп,finitу: (О } ",
doubl.e. РоsitivеInf'lпi ty! .;
COMJole .Wri teLine (П -> dO\lble. Ne.ga t,i vel[:nfiait у ~ j О} " ,
doJ:Щlе . NеgаtiVfil~J.n.itу) :
СО.шsо1е. •.Wri teLi 'Qe (" -:> double-. t-1ах\7;аl iJе: j.o 1", d01;Jb le .мaxVEйue) i
соnэоl.е ,Wri teI.ine ("->dJ)Ublе,.furNаlЩ6: {:O:l ", ,dщiblе .МinValueJ ;
180 Часть 11 . Язык программирования С#

Члены System. Boolean


Теперь рассмотрим ТИII данныхSystem.Boo1ean. В отличие от С(++). в С# един­
ственными возможнъrм;и значениями ДЛЯ boo1 являются Itrue I fa1se}. В С# вы
не можете назначать типу boo1 импровизированные значения (например. -1. О. 1).
что считается (большинством IIpограммистов) IlРавильным нововведением. С уче­
том этого должно быть понятно. почему System.Boolean не Ilодцерживает свой­
ства MinVa11le/MaxValue. а Ilоддерживает Tr1leString/FalseString.

// в С# не')! npоиsвOJlIoНWX '1'ИПо. Boolean'


bool Ь = О; / / Не,цопусo:rико!
bool Ь2 = -1; /1 Тах-е ие,цопустино!
bool Ь3 = truei /I Без npоблен.
boo1 Ь4 = false; 1/ Беs проблен.
Сопsо1е.WritеLiпе("-> bool.FalseString: (0)", bool.Falsestrinq);
Сопsо1е.WritеLiпе("-> b oo l.Tr ueS tring: (О}", bool.TrueStrinq);

Члены System.Char
Текстовые данные в С# представляются встроенными типами данных string
иchar. Все . NEГ-языки отображают текстовые типы в соответствующие базовые
типы (System.String и System.Char). Оба эти ТИIIа в своей основе используют
Unicode.
тип System.Char обеспечивает широкие функциональные возможности, дале­
ко выходящие за рамки простого хранения символьных данных (которые, кста­
ти, должны помещаться в одиночные кавычки). Используя статические методы
System.Char. вы можете определить, является ли данный символ цифрой, буквой,
знаком nyнктуации или чем-то иным. Для иллюстрации рассмотрим следующий
фрагмент программного кода.

static void Main(string(] args)

// ПроверЬ'J!е рабо'J!У сле,цующкх onepa'J!opo•...


Сопsо1е.WritеLiпе("-> char.IsDigit('K'): (О)",
c har.IsDiqit('K'));
Сопsоlе.WritеLiпе("-> cha-r.IsDigit('9') ; {О}",
char.IsDiqit('9'»);
Сопsо1е.WritеLiпе("-> char.IsLetter('lO', 1}: 10)",
char.IsLetter("10", 1»);
Сопsоl е .WritеLiпе("-> char.ISLetter('p'): {О)",
char.IsLetter('p'»;
Console.WriteLine(n_> сhаr.IsWhitеSра се ('ЭЙ, там!', 3): {Oj",
char . IsWhiteSpace ("Эй, там!", 3»;
Сопsо1е.WritеLiпе("-> сhаr.IэWЫtеsра с е('ЭЙ, там!', 4): (О}",
char. ISНbiteSpace ("ЭЙ, там!", 4»);
Соn sоlе .WritеLiпе("-> cha.r:.IsLetterOrDigit(' ?'): (О)",
char.IsLetterOrDiqit('?') );
Сопsоlе.Wri tе Liпе("-> сhаr.IsРuпсtuа t i ол (' ! '): (0\",
char.IsPunctuation(' I '»;
Глзвз З. ОСНОВЫ языка С.# 181
С'0л.sеl.е. WriteLine (" -;> t:ha.r. IS'P unctuation ( '>' ): ,{.О J"•
char . ul?UnC!tuq.tlon ( '>') -) ;
С'~n:эоlе. Wl-it€liJloе (""-> cfi ar. 1 sPLinctuatioГt (' , , ): j б Т" ,
~Ъ.aт . ISРШlсtuаt,.iоn ( ". ' ) ) ;

Ka,g видите. Щiя всех ЭТИХ crrатических члеJ;lОВ Sуstеm.СIщт при ~Ы.зове ИСДОдЪ­
зуетоя следУЮщее (ЮГJ'ЫШение: следует YR'oiIзать J,!Ибо еДИНственн1>IЙ Cn~IliOJ1. лиБQ
~poкy с чисдовым индексом, ко-rорьtй yR1;!.3ыв~TT мёстоположение проверяеМ0l10
CДМi1oдa.

Анализ. значенийстроковы)( данных


тиды д<iRнь1.x .NEТ обеспечивают .вО~OOЩiОСТJ> .генерировать переменную того
типа. который gaдaется данным TeKC'I'OВblM э"КВ'.щщлеНТОМ (J".e. ВЫПQЛНЯТЬ ctl1Щ1ЦЮ­
CUt(eCК'tIIl aнtVW3). Эта ВО3МОЖJ-10Cn может ОRaЗaТы;щ чрезвычайно ПOJIезnой тогда.
IЮГДq требуется upеобразовать ВВОДимые пол:ьзо:вате.ilСМ данные (:например. выд-­
денные в РIШЪ.<рЫIШJощемся списке) J,f числовые знэчения. Ра(;смотрите слtдующий:
фраI'~ент прorpаммtюго кода.

-sta.tic V'oi,j Mai!'i (' 8triл"1:[] args)


{

bQol lТ1'~/Boi::'l = 11001. Раrзе ("'I'rш?") ;


C011s01 е. Wri t eLihe ('" -;. зна'!еР.~е myEool: 1О')' "1 шу8шJl);
ct0'Jble :/'цуDbl = c:fьublе . .Раз:$~(Н99,884"J;
СО1}$1.;lе. Wr i-tеLiле ~.,,-> 'Знаqение myDbl: \:01" I myDbl ~ ;
int. rnуlпЕ = int.Parse("8") 1
СС1nзсЙе. Wrl·teLine ("-::> Значеl'l:ие mуlпt: f О t 11. шуlПtJ';
chgr myCtlar = cn·a :r . 'Раnе I п w П);
Ссшsоl-е. Wr i teLine ("-); 3наЧSJ?ие myCrlax;;1 'О J \в", J1"lусЪаr);

System.DateТime и System.ТimeSpan
в завершеНйе нашего обзора базовых типов ДillJ;Н:ЫХ позвалнге обратить ваше
внимание на '1'.0'. ЧТ(l) пространство имен Syst ет одределяет нес1ЮЛЬКО ПОдеЗ1U>LХ

ТИПОВ дапных. ДЛЯ которых в С# не, цредусмотрено ЮIЮчeвblX слов. Это. в qacт­
~()сти. ·тшrы D.at:el'ime и TimeSpan (задачу :ИСCJI6ДQван:ин ТИПОВ System .Gl1id и
Syst;em .'Vo1d. которые среди про~ ЦОIЩЭаны I;Щ рис. 3_19. мы оставляем на усм.о­
J'ре:рще aaн:в:TepecOBa1mЫX ЧИ1'ателеЩ.
11щ Dat-€'Iiтe соДержит данные. представлнющи;е коннретные дату (месяц. день,
j"OД) и время. которые можно отформатировать РJiЗЛИЧНЫМИ cnособа:.1\о1И с ПОМ:ОЩЫо
соотвеТ('твующюt членов. Е качестве ЩЮСТОГО прщ.1ера рассмотрите слецуюrщПi
набор операт.оров.

stiЭtiс void Main (.$tring-[) aJrg9)


1
...
182 Часть 11. Язык программирования С#

1/ Этот конструхтор иcnоnьsует (год, месяц I день)


DateTime dt = new DateTime(2004, 10(17);

1/ Какой это день недели?


Сопsоlе.WritеLiпе("День (О) - это (11",
dt.Date, dt.DayOfWeek);
dt.AddМonths(2); // Теперь это декабрь.
Console. WriteLine ("Учет летнего времени: (О 1",
dt.IsDaylightSavingTime()) ;

Структура TimeSpan позволяет с легкостью определять и преобразовывать еди­


ницы времени с помощью различных ее членов. например:

static void Main(string[] args)

1/ Этот хоиструктор использует (часы, МИНУТЫ, сехуиды)


TimeSpan ts = new TimeSpan(4, зо, О);
Console.WriteLine(ts) ;

11 Вычте" 15 мину'l' из текущего sначеНИR TimeSpan и


/ / распечатаем реsультат.
Console.WriteLine(ts.Subtract(new TimeSpan(O, 15, О)));

На рис. 3.20 показан вывод операторов DateTime и TimeSpan.

Рис. 3.20. Иопользование типов DateTime и TimeSpan

Исходный код. Проект DataTypes размещен в подкаталоге, соответствующем главе З.

Тип данных System.String


Ключевое слово string в С# является сокращенным обозначением типа System.
String, предлагающего ряд членов, вполне ожидаемых от этого класса. В табл. 3.12
предлагаются описания некоторых (но. конечно же. не всех) таких членов.
глава 3. ocнoBы ~3bIKa Cft 183
ТабтщаЗ.1~J HeJroTopble 4леНЬ!Sуstеm..Stri,ng

Член ОомсаRИе
Lengtt1 ОвоИоrво. ВGавращающее длину 'Текущей .СТРО1<И
сооt.аiщ~ · О МеrсОД, пр",меНЯeN\i;J.IЙ ДПЯ выяснения ТаТа, содержИ1 111'1 1екуlJ,l,ИЙ СТРQКDВ15IЙ
Сlбwkт даJ;J;Ную строку
Format () 'Стаnl'lескии метОд., применяемый для фQJ,)матираВflНlIIЯ сrРЙJ<Ь8Ьi)( лМтераПО8
С ИСГЮЛD3cJВa/iием примитивов (ЧИ\::110ElpJХ дa~I~JblX и дрv.rих строк) и ОQозна4е­
Щ"14 типа j 1).\ ,уже встречаВШИХСR' ранее в этой {,паве
l!)s~rt () MeroJJ.. ИCfl,ФI1ьзуемый ДЛЯ получения КОПИИ текуЩей СТРОКИ , содержащей до­
баВmlемые СТРО1(081;)[8 даННt>/е
.P adlieft () МетоДЫ, возвращаЮЩие I<ОIН1И т~кущей CTpO'-I'I" дополliеf:lf,iЬ/е указэнныIII
J?adRiqht (1 ЛII~JHbIМJII в качеctВе заПОI1нитем
Remo,;!e ( ) Методы , ИQЛольэуемые ДЛЯ ПVJlуЧ'еНmt !(опии сороки с С~)QТВeтG1ВуюЩИМИ 1010-
Е.ерlасе() диQ>.l.1КЩI4ЯМИ (п.Ри удаленllWl или заме~lе СИМВОлОВ)
S'u]:)stril'Jg () Меroд, возвращающий строку, которая предСТЗ8ляет подстроку щкущей СТРОКИ
ToCi::IarAr)';a~"( ) Метод, возвращающий маССИ1l сltfМВОЛQВ, из которых еоатоит те~ущая стрща
T0Upper(J Методы, создающие КОПИIIiJ Д!&lНОЙ строки, предстаВJiенную СИМВОIlами в
Тф,оwеr () 'bepX1-lем ИJ:1и, COdТBeYCтtteHI'tO, НИЖIi~М регистре

Базовые операции со СТРОl(ами


дли ИЛ.1lЮстрации некоторых: бцзовых оцераций со стрorщми раССМО'ГРИМСМДУ­
ющий метод Mai n ( ) .
static voic Main (;,:ч:..r iпg [) д; rgs I
[
Console . Wr i teLine '( " ** ~ * * Зао:авы СО' СТрО~l'Й1. " .,. "''' '') ;
$1::r-ing Е' =' ,1 Воу, t.b is is ,taking а 10(19 t iщ;:? "';
, <: олsаlе,. 'WritеLiПе("--> С одеР)frЯТ ли s 'ау'?: jD)",
s . Contai.ns("оу" ) ) ;
C(,\Jls01e.W.riteL~[[>e ("--> СО'nеРЖI4'l' ли s 'В 9У '?: (DJ ",
э. COntafns ("воу"
) J ,;
Console,WriteLine ,(.s. .,Replacel'.', 'J'));
с.1\)!1stIJ1.е.t"1litеLiпе(З.Iщsrt(О. "НО,! 01 "));
CQr,csol€. Rе,э.dЦiГJе () ;
}

a~ъ..мы Cd:щаем тип s.tri пч, аызьmающий методы' CGHlta iпs О . Eepl.ace (,) и
Iпsеrt (). Соотвeтr;ТВУЮЩИ:Й В:ЫВОД показЭ1:I на рис. 321_

Рмс. 3.21. Базовые onерации со строками


-
184 Часть 11. Язык программирования С#

Вы должны учесть ТО. что хотя 5tring и является ссъmочным типом. операции
равенства инеравенства (== и ! =) предполагают сравнение значений со строковы­
ми объектами, а не областей памяти, на которые они ссьmаются. Поэтому следУЮ­
щее сравнение в результате дает true:
5tring 51 = "Не110 ";
5tring 52 = "Не110 ";
COn501e,WriteLine("51 == 52: (Ol", 51 == 52);

тогда IЩ}{ следующее сравнение возвратит Еа15е:

5tring 51 = "8е1 10 ";


5tring 52 = "World!";
COn501e.WriteLine("81 == 52: {O l", 51 == 52);

Для конкатенации существующих строк в новую строку. которая является


объединением исходных, в С# предлагается операция -1-, RaR статический метод
String .Concat (). с учетом этого следующие операторы оказываются функцио­
нально эквивалентными.

/I Конкатенация строх.
5tring newString = 5 + 81 + 52;
COn801e.WriteLine("8 + 51 + 82 = {О}", newString);
COn801e.WriteLine(n 5 tring.Conca t (5, 51, 82) = IО} ",
5tring.Concat(8, 51, 52) );

Другой полезной возможностью, присущей типу string, является возможность


выполнения цикла по всем отдельным символам строки с использованием СИНТaR­

сиса, аналогичного СИНТaRСИСУ массивов. Формально говоря, объекты. подцержи­


вающие доступ к своему содержимому. подобный по форме дос'fYIIY к массивам,
используют метод индеlCсаmора. О том, как строить индексаторы, вы узнаете из
главы 9, но здесь для иллюстрации соответствующего понятия предлагается рас­
смотреть следующий фрагмент программного кода, в котором 'каждый символ
строкового объекта в1 вьmодится на консоль.

// Sуstеш.String опредеnяет индексатор ДЛЯ доступа


// к к_дому символу а строхе.
f or (int k = О; k < 51.Length; k++)
COn501e.WriteLine("Char [ О } i5 {l}", k. sl[k]);

в качестве альтернатив,Ы взаимодействию с индексатором типа можно исполь­


зовать строковый класс в конструкции foreach. Ввиду того, что System.String
поддерживает массив индивидуальных типов System.Char, следующийпрограмм­
ный тоже выводит каждый символ 51 на консоль.
foreach (char с iп sl)
Conso1e.WriteLine(c) ;

Управляющие последовательности
как и в других языках, подобных С. строковые литерaльr в С# могут содержать
различные управляющие последовательности. которые интерпретируются как

определенный набор данных, предназначенных для отправки в выходной поток.


[лава '3. ООНЬЖЫ языка с# 185
Каждая упрЩJJШiOща.в последовательность на.<1й1Щется: с Qбратной 1I:0СОЙ черты. за
~оторQЙ~. llе'дует интеpupетируеМЬ1Й зНaR . На тот сЛ)'Ч<Щ. ~JЩ вЫ пQдз:а.Быml зна­
чеюш уцравJl.ЯiЮЩИХ последоВательностей. в та.бл. 3.13 предлarаютоя ОI1ИCаня.я тех
из них. которые иtпОЛЬзyJотся: чаще всего.

Табтtца 3.1,3. Управляющие ПОСП8доваТеl1.ЬНОGТVI строковых литералQ8

УправЛllJOщjtя
O"K~aнмe
посnеД08а:rел,"носп.

\1 Вставляет в СТРОICОВEi1Й ли.тералЗН8J( ОДИНDЧАоiil JfflВЫЧ'к и

\" BCтaВJ1~eT 11 сrРОI<ОВЫЙ дитэрал 'знак ДВОЙ!-10Й кавыi<ии


\\ BcraВ:nl;leT встроковый ЛИl'ераЛЭI'lЭk 'Обратной КОСQЙ черты',
Это может оказа:rъся п'олеЗНblМ при укаЗЗНlII1II П'(11l

\а Инициирует системt-IblЙ::IВ'УICОВОЙ сигнал (be~p). Для консоnы-lых


припожеl1l-1И это может быть аУДИОrlодскаЗКQЙ пользователю

\n Вставляет знак перехода f.l8 HOBYJ() cтpo~ (н.а платформах Wm32)


\r Вь,.а!;l'ЛЯ~Т знак ВОЗВРilта каретки

\t Всщвляет в СТDО~ВЫЙ литерал 3НЗIC ГОРIIIЗОНТал'ЬНt>й Табуляции

Ta.k, чтобы напечаТать строЕУ. в цотuрой между любыМи двyr.m словами ИМеете$'!
3НaI< табуляции. МОЖJIО Иt:'полъ:roватъ }"Цра:вляющую лоследо.ватеЛЬН1LIСТh \ t.
1/ Cтpo~o.ыe ~e~· Mor:y'J1 со;цераа.'1'Ъ mDбое ЧМQJ.IО
11 ynpав.1IJlDЦИX nо.cnеДова'1'еnькос",,9Й.
string 53 = Л'Эй, \ t!3bl , \ t'1'ёЩ!, \ t олят ь 1" ;
:COlisole. Wr i .teLine ("53) ;

для другого прm..Jера предиоложим. "ГГО вам .нyжI:IО с{}'здат~ Сl1ЮRОвы:'Й литерал.
Itотор1!IЙ содержит НаБЫЧКИ. литерал. указьmаюIIЩЙ путь в: HaTa.j]ory~ п. наконец,.
литерал, КОТОРЫЙ' :вeтaвJJHeт три Пустые СТРОRИ после вывода l!!uex L'ИМВЬ.!lbliЬJX дан­
ных. Ч;тобы не допу.с1'И'tЬ nолвлени:s: сообщений об опщбкщ НОМПИЛ1.ЩЙИ, исполь­
зуйте ур.раБЛНЮщи:е СИМВОЛЫ \ ". \ \ и \n.
Соnэоl е • Wri teLi!"'!e ("Все .Ilю('}:я.'r \ "Неl10 Wor-ld\ n "J; Сопsо1е.
Wri tеLiПе" (" 'С : \ \МуАрр\ \Ьin' \ \d-e·b ug") ;
еопэсЙе., W~ i teLirle ("Все за:аершенр. \п\п \n:") i

Буквальное воспроизведение стро,к в С#


в С# ВВОДИТСЯ И'спольЗование префик.са @ ДЛЯ cтpo.!t , 1\О'горые тр.ебуется вocnpo­
uз!3ecrnu БУКВQJ!ЫШ. Используя букв:;щьное воспроизвеДение стран, вы ОТltЛlочаете
обработку управляюших сifМВоло.в строк. 81"0 может быть полеэnым при работе со
строками. представЛfl1ОIЦИlI,Ш Rаталоги и сетев:ые ЦУТИ. Тогда вместо nСПОЛЪЗОQа­
ния y:npaвляющих СИМВОЛО:$ \ \ можно И:СПОJlliЭОliаТЬСЛедУЮщее.

11 СnедYDЦ&1'r c>zopoJ:a ДО.цм;1ji1 · аоcnpоиs:аоДlП'loСН буца.т.во,


11 ~рэ~оиу :асе I vарaJJJ1RX1ЩИ1I!I cюraОml" б:у;цу~ O""O~.IU!t.
Coosole. WriteLine {@"С: \'My,App\biQ \cj.eb 'lg") ;
186 Часть 11. Язык программирования С#

Отметьте также и ТО . что буквально воспроизводимые строки могут использо­


ваться для представления пропусков пространства в строковых значениях, ~pac­
тянутых" на несколько строк .

// в буквально ВОСПРОИSIIОДИМЫХ строках


/ / пропус!щ ПРОС'.l'pаНСТllа сохраюlЮo:tIся.
s tr ing rnyLongString '" @ "Это оч ень
оч ень

о ченъ

длинная строка ";


Со пs о l е.W ritе Liпе( mуLоп gStriпg) ;

Двойную кавыч:ку в таl<ОЙ строковый литерал можно вставить с помощью ду­


блирования знака ". например:

Console . Wri te Li ne( @" Cerebus said ""Darrr ! Pret - ty sun-sets""");

Роль System.Text.StringBuilder
тип зtriпg прекрасно подходит ДЛЯ того. чтобы представлять базовые строко­
вые переменные (имя. SSN и т. п . ). но этого может оказаться недостаточно. если вы
создаете протрамму. в КОТОРОЙ активно используются текстовые данные. Причина
кроется в ОДНОЙ очень важной особенности строк в . NEг. значение строки после ее
определения изменить нельзя. Строки в С# неизменяемы .
На первый взгляд. это кажется невероятным. поскольку мы привыкли присваи­
вать новые значения строковым переменным. Однако. если про анализировать ме­
тодыI Systern .String. вы заметите. что методы. которые. как ка;жется. внутренне
изменяют строку. на самом деле возвращают измененную копию оригинальной
строки. Например. при вызове ToUpp er () для строкового объекта вы не изменяете
буфер существующего строкового объекта. а получаете новый строн:овый объеICТ в
форме символов верхнего регистра.

s ta tic void Main(string [] args)

/ / Думаете, что иЗменяете strFixed? А IIОТ и не'1'!


Sys tern .S t r ing strF ixe d = "Т ак я начин а л свою жи знь";
Console.WriteLi n e(strFixed) ;
string upperVersion = strFixed.ToUpper();
Console.WriteLine( strFixed);
Console.WriteLine("{O}\n\n", upperVersi on );

Подобным образом. присваиван существующему строковому объекту новое зна­


че ние. вы фактически размещаете в процессе н.овую строку (оригинальный строко­
вый объеI<Т в конечном итоге будет удален сборщиком мусора). Аналогичные дей­
ствия выполняются и при КОНRатенации строк

Чтобы уменьшить число копирований строк. в пространстве имен Systern.Text


определяется класс StringBuilder (он уже упоминался нами выше при рассмотре­
н ии Sy stern.Object). В отличие от Sys tem.String. тип StringBuilder обеспечивает
Глава З. Oct1~B'bl язЫКа С# 187
прямой доступ к буферу строки. ПодобklО SysEem.String, тип Эtrin.gВ1'lildеr пр~д­
латает МlЮжecnю "f.шенов. ПО3IЩnЯlШТ{I.,Ц добавл.вть, форматирова1'Ь. щ::т.авлятр и уда­
ЛЯ'tЪ p;aJiНЫe (подробности вы найдете в ДОRy-ментации .NEТ Framewor~ 2.0 SDк).
При создании оБЪеКта StringBui J:de:c М0ЖJ;10 указа'rЪ (через ap:ryмeН1' КСЭflСТР,yR­
'тора] начальное число СИ:Мl:IQЛОВ. КО1'ор(}е может СDдержа-nь об-ьеn Если этого ВЕ'
сделать. '[о буде1' ИСПQЛЬЗоватьCJi "стандарТНr'lЯ. емкость' Str ingHu i1.der, по умол­
чанию равная 16. Но в любам 'CJIj'Ч4е. ~СЛИ выУВ<;>ЛИЧИте St:ringBuilq-еr бощ,ше за­
данного числа символов. то размеры буфера будУТ переопредe.nены динамичеСIШ.
Вот пример ИCUОДЬЗОВ<Ш:ИIl этого типа у.лareа.

11s,il)g S:'t·stem.;
4.siлg SY$t,em,Тe~ti !1 Эдесь ) JPfВe11" str.ingВuilder .

Cla,,8 'S:tr iпяА.рр


I
s tatic ll~i.d Mai.n j striDg [] args)
j
StJ;'iлgtlui1dеr m;yBuf'fer = Ш,'W s!:r.:!.ngБUildеr:("МОЯ· СТРО'ка");
Ccas.ole. Wri te-Liae ("Емкость ЗТ,QГQl St.y;i r!gB,uilder: {О]",
,.Ca.paqi ·ty) ;
(nуВцffеr
щувuf fer .Append (~ содержит также ~ИС'.д·Е!: ");
rrryBuf'fer.AppendFormat("jO} , р}.", 4-4, 9~n;
f.;с,n:юli'!. W:ri teLi.!le ("~CTё '"'того s·tringB\Jildar: ! О}" I
my.вuIfer.Capacity);
СОI'1З0'lе .. W:r.i teLine (туВи[ fei:') ;
}

Во' Многих случаях наиболее подходящим длнвас текстовым объектом бу,дет


5уэtе'l1l. Зtring. i'J,ля UОЛЬiUЩiства приложени'й потери. СВЯ3аНllЫе с ВQ;з.вращени­
ем иэыен:eннъrx КОffiх.Й сИМ)ЗольН!>lX данн;ых, буцут везнзчптелыlми.. Oдuaкo цри
цостроеНШI приложmmй, nНтеНCИJ3lfО ИСПОJIl:!зуЮщ:их тстстовые дaнnыe (например,
1"ef!:стов:ыхпроцессоров]. nl, скорее всего, обнаружите. что JfCIIОJ.lЬ30вание Syst€\1t1.
I'ext. Stri{]gHuilder повьцuaет ДРОИЗВQЩIтельвость.

ИСJlОАНЫЙ Kq~, Проект :Strings размещен Q по:цкаталоге, сщпвететвующем r1IВBe З.

Типы массивов. NET


Формащ.но fOBOPR, массив - ЭТО ко.тmеh'ЦИЯ указателей на дав:ны.е одн.ого u IУЮг:О
:же вполне (щределе:inrо:го ТlJпа. доступ I'С которым осуще~твляется. JЮ числовому

ШIДeRСУ. MacUffibl двляЮтCR ссы1Iочнымй типами и получаЮТСЯ из общего базОВОI'О


K'Iacca 5y~te-m .Array. По умолчанию для .NЕТ-:t,'laе~и;вов начfl.льный индекс равен
н.ул1О, .НО С помощью статического метода Эуst~.m.Аrrа.у,Сrеа.tеInstа.nсе О ,цля
любого массют М9ЖНО задать любую НИЖ1:tюю гран:.и:цу ДJЩ ·его индексов.
МаосивЬ1 ц С# можно объявлЯть,nо-разиому. Во·первых. если вы хотите создать
массив. значеНИR которого· будут опреде.деНbt позже (~озмomпо лосле ввода ооот­
ветствyYQЩЩ<: Дt'Ц-.IНЬJ.X ttОJThЗ0вател:ем). то, ИCllо.дьауя I<ВaДpllTHble скобки (л). yI<aжII­
те размеры массдва во время его создания. Н.алример:
188 Часть 11. Язык программирования С#

11 Создание массива с'1'рох, содержащеro 3 элемента {О - 2}


string[] booksOnCOM;
booksOnCOM = new string[3];
11 Икициa.nизаЦИR lOO-злеиеаorного массива с нумерацией {О - 99}
string[) booksOnDotNet = new string[1001;
Объявив массив. вы можете испольЗовать синтансис индеl\.сатора, чтобы при­
своить значения ето элементам.

11 Соs.цание, заполнение и печать массива из '1'рех С'1'рОХ.


string [} booksOnCOM;
booksOnCOM = new striпg[З);
book sO nCOM (01 "Developer's Workshop to СОМ and ATL 3.0";
booksOn COM(l) = "Inside СОМ":
booksOnCOM (2] = "Inside ATL";
foreach (string s in booksOnCOM)
Console.WriteLine(s) ;

Если значения массива во время его объявления известны. вы можете исполь­


зовать "сокращенный" вариант объявления массива. просто указав эти значения
в фиrypных скобках. Указывать размер массива в этом случае не обязательно (он
вычисляется динамически). кан и при использовании ключевого слова new. Ta1t.
следУЮщие варианты объявления массива э1tвивалентны .

11 'Краorхий' вариант об~леник массива


11 (значеНИR во вре_ об....леНИJI ,цоJtЖJВ1 БW"1'1o иsаестНJoI) .
int(J n=newint() {20, 22, 23, О};
int(J п3 = { 20, 22, 23 , О };

и нанонец. еще один вариант создания типа массива.

int[) п2 = new int[4] { 20,22,23, О }; /1 4 элемента, {О - Э}

в данном случае указанное числовое значение задает число элементов в масси­


ве. а не граничное сверху значение для индексов. При несоответствии между объяв­
ленным размером и числом инициализируемых злементов вы получите сообщение
об ошибке компиляции.
Независимо от того. 1taн вы объявите массив, элементам в .NЕТ-массиве авто­
матически будут присвоены значения, цре,цусмотренные по умолчанию, coxpaнmo­
щиеся до тех пор. по1tа ВЫ Yl'ажете иные значения. Тан, в случае массива числовых
типов, каждому его элементу присваивается значение О (или О. О в случае чисел с
плавающим разделителем). объектам присваивается null (пустое значение). а ти­
пам Boolean - значеНl~е false (ложь).

Массивы в качестве параметров


(и возвращаемых значений)
После создания массива вы можете передавать его. 1taн параметр. или получать
его в виде возвращаемого значения. Например, следУЮЩИЙ метод PrintArray ()
получает входной массив строк и выводит каждый злемент на консоль. а метод
GetStr ingArray () "наполняет" массив значениями и возвращает его вызывающей
стороне.
Глаза Э. ООНОВЫ языка С# 189
statLc 'fold Pr1nthrr,ay (inttJ 'DlyZntз)
{
for (i.пt i = О~ i < mуlлts. :Len.gtJ-.,· i ++ )
Сопзоl е . Wri teL.1,ne ("ЗJ1, е~ент {О) равеf'l (l}", i, roylл'сS' [i] ) ;

stat.icsUing [] G"tStrin.gATray ~)
(
str.ir1ЧjJ thеStr:iЛ;jВ = ! "ПрИвет", "с' т", "GetStringArray" };
,r -et.urn thеStri.ngэ;

Эти .метсщы МОЖНО вызвать из метода Main О. хан. пока.,·WНQ ;!iИже.


$tatic vcid l'1aln (gtring!] эр;!;;,>' )
(
in"t,lJ ages, = {20, 22, 23, О) ;
PrintArzay (ages,) ,;
s:ti: iпg 1] 's t rЗ = GetStringAz:ray (1 :
fDreacb~string s i n strs)
Caг.s() 1.е . W'r i t.eLine ('09) "
console . Rещ:lLiпе ~) ;

Работа с многомерными массивами


Вдобавоlt к ОДl-IOмерным массщщм, ~oтopыe мы рас~атривали до СИХ пор. 11
С# подцержива:ются два в~риавта многомерных Maccnвo:в.. Первый из RИК- это
Тlр.ямауооЛЬНbtЙ массив. Т.е. ммотомерный ~СCЩi-, Б .котором RШfЩая СТрО1>а оказы­
вается однои и той же длины. Чтобыоб~.Ii!'JЪ"И заполнить многомерный прямау·
лшьный массив. действуйт~ Тан,. как JJоказано НИЖfl.

э!;.аЦс void Ma.:inisUi ·r .g[] а!'ЯВ)


{

11 ПрmюyrоJIЬ.!WЙ массив МD.


irlt [, ] myMatrix;
,l1'\yMatri,x = a~\'" iпt16,БJ:

11 Зanоnяе.кие массива (6 ,. Ei).


f 'o1' 1irit i = О; i <: 6 ; д +-+ }
for(ir.t j = О; j <. б: :1++1
myMa t r~x (:i., j] = 1 * J;
/1 Печать массива (6 * '6).
forCint i =0: i '< 6; i++)
I
for ( in t j =01 j < 6; j-+
СолщЙе.Wгitе(m>tМаtriх[ir j) -+ "')"t~);
Consble. Wri :teLitle () ;-
190 Част ь 11. Язык программирован ия С#

На рис . 3.22 показан соответствующий вывод (обратите внимание на прямоу­


гольный вид массива).

Рис. 3.22. Многомерны й массив

Второй тип многомерных массивов - это невыровнен.ныЙ массив . Как следует


из самого названия . 'ГaJЮЙ массив содержит некоторbIЙ набор массивов. каждый
из которых может иметь сво й верхний предел для индetссов . Например:

stat i c void Маiп(s tгi п g[ 1 a r gs )

/ / неsыpовненный массив МD ('1'. е. массив мa.cCJВoa) .


1/ Здесь мы имеем· массив из 5 разных маСCJOов .
int[ ] [ ] ш уJаgА rrау = new i nt [ 5 ] [];

// Создание неawpовненного массива.


fo r (in t i = О ; i < myJagArray . Leng t h ; i ++)