Академический Документы
Профессиональный Документы
Культура Документы
~ w w.willfamsрubIisl,ing...оm
Apress
;;
Эндрю Троелсе н
языK ПРОГРАММ'И'РОВАНИЯ
С#'2005
И ПЛАТФОРМА .NET 2.0
3-е из,дание
Эндрю Троелсен
Троелсев, Эндрю.
Т76 Язык программирования С# 2005 и платформа .NEТ 2.0. 3-е издание. : Пер.
с англ. - М. : 000 "и.д. Вильямс~. 2007. - 1168 с. : ил. - Парал. ТИ1: ангЛ.
ISBN 5-8459-1124-9 (рус.)
ББК 32.973.26-018.2.75
ответствующих фирм.
Никакая часть настоящего издания ни в к;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.
Оглавление
Об авторе 30
Благодарности 30
Введение 31
Вы и я - одна команда 32
Обзор содержимото .книги 32
Часть 1. Общие сведения о языке С# и платформе .NEТ 33
Часть П. Язык программирования С# 33
Часть т. Протраммирование компоновочных блоков .NEТ 35
Часть IV. Протраммирование с помощью библиотек .NEТ 36
Часть У. WеЬ-приложешm и Web-сервисы XМL 38
Исходный код примеров книги 39
От издательства 40
Люблю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:стру
Вы и я - одна команда
Публикации разработчиков новых технологий предназначены для очень требо
вательной аудитории (я должен знать это не понаслышке - ведь я один из них).
Построение программных решений дл1f. любой платформы требует чрезвычайной
детализации и учета множества особенностей соответствующей отрасли, I-tOмпа
нии, .клиентской базы, а также учета сути дела. Вы можете работать в электрон
ном издательстве, разрабатывать системы для федерального или местного пра
вительства, работать в NASA или каком-то оборонном ведомстве. Я, например,
разрабатывал программное обеспечение для обучения детей, создавал различные
N -звеШfЫе системы и участвовал в многочисленных проектах для медицшlСКИХ и
финансовых учреждений. С вероятностью почти 100 процентов тот программный
код, который вы создаете на своем рабочем месте, не имеет никакой связи с про
граммным кодом, который пишу я (если, конечно, нам случайно не приходилось
работать вместе).
Позтому в этой книге я сознательно избегаю примеров, в которых программный
код связан со спецификой определенных отраслей производства или сфер про
граммирования. Я пытаюсь описать возможности С#, объектно-ориентированно
го подхода, CLR и библиотек базовых классов .NET 2.0 с помощью примеров, не
использующих такой специфики. Вместо того чтобы в каждом примере заполнять
таблицы реальными данными, рассчитывать платежки или выполнять КaI(ие-то
другие специальные вычисления, я буду рассматривать объекты, с которыми могут
иметь дело все, - например, автомобили (с их геометрическими формами и слу
жащими соответствующего предприяти1f.', добавленными для полноты картины).
И'ryТ на сцену должны выйти вы.
Моей целью является как можно более понятное объяснение возможностей яэы
ка программирования С# и описание различных аспектов его применения в рам
ках платформы .NEт. Я сделаю все, что будет в моих силах. чтобы вы, используя
знания и навыки, полученные в процессе работы над этой книгой, могли продол
жить дальнейшее освоение соответствующих технологий.
Вашей целью является освоение этой информации и применение ее к вахпим
конкретным задачам программирования. Я, конечно, понимаю, что ваши проекты
вряд ли напрямую связаны с автомобилями, имеющими имена домашних любим
цев, но так уж заведено в прикладных науках! Уверен, если вы поймете КОfЩепции
платформы .NEт. представленныe в этой книге, то сможете предложить и реализо
вать решени1f., подходящие ДЛ1f. вашей конкретной среды программирования.
ИОХОАныЙ "о,ц, 8 таком при-ме'Jан.ии 'Ук<!з~!Ваетi::я сqЫЛJql на I(атэ.лor, содержащий ИСХОДНЫЙ "ОД
соотвеТСтвующего примера.
Связь с автором
Если У вас :во:ш: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
Информация для писем из:
ЧАСТЬ I
Общие сведения
о я3ыIеe С#
и платформе .NET
ГЛАВА 1
Философия .NEТ
го ненадежных.
Подход C++/MFC
Огромным шагом вперед по сравнению с подходом, предполагающим использо
вание C/API, явился переход к применению языка программирования С++. Во мно
гих отношениях язык С++ можно рассматривать, как объектно-ориентированную
надстройку над С. Поэтому, хотя при использовании С++ уже можно использовать
преимущества известных "краеугольных камней ООП" (инкапсуляция, наследова
ние и полиморфизм), зтот подход оставляет программиста во власти многих болез
ненных аспектов языка С (управление памятью "вручную", безобразная арифмети
ка указателей и ужасные синтаксические конструкции) .
Несмотря на сложность, сегодня существует множество каркасов программи
рования на С++. Например, MFC (Microsoft Foundation Classes - библиотека базо
вых классов Wcгosoft) снабжает разработчика набором С++-классов, упрощающих
создание Wiп32-приложениЙ . DIавной задачей MFC является представление "раз
умного подмножества" Wln32 АР! в виде набора классов, "магических" макросов и
средств автоматического генерирования программного кода (обычно называемых
мастерами). Несмотря на очевидную пользу указанного каркаса приложений (как
и многих других средств разработчика, использующих С++), программирование на
С++ остается трудной задачей, и на этом пуги нелегко полностью избежать ошибок
ввИдУ ·тяжелоЙ наследственности", обусловленной связью с языком С.
Подход 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оцесса разработки бинарных СОМ-объектов было создано
множество каркасов разработки приложений с поддержкой СОМ. Среди них. на
пример. библиотека ATL (Active Тemplate Library - библиотека активных шабло
нов). которая обеспечивает еще одно множество С++-классов. шаблонов и макро
сов. упрощающих создание СОМ-типов.
Многие другие языки также в значительной степени скрывают инфрастрyк'Iy
ру СОМ оТ глаз программиста. Однако поддержки самого языка оказывается не
достаточно для того. чтобы скрыть всю сложность СОМ. Даже при использовании
относительно простого совместимого с СОМ языка (например. VБ6). вы все равно
вынуждены бороться с "хрупкими" параметрами регистрации и многочисленными
npоблемами. связанНыми с инсталляцией приложений (в совокупности называе
мыми "кошмаром DLL") .
Решение .НЕТ
Слишком много для короткого урока истории. Основным выводом является то,
что жизнь программиста Windows была трудна. Каркас .NEТ Framework является
достаточно радикальной ~силовой" попыткой сделать нашу жизнь легче. Решение,
предложенное .NEТ, предполагает ~изменить все" (извините, вы не можете обви
нять посыльного за такое известие). Вы поймете из дальнейшего материала книги,
что .NEТ Framework- это совершенно новая модель для создания систем как в
семействе операционных систем Windows, так и множестве операционных систем,
отличных от систем Microsoft, таких как Мас OS Х и различные варианты Un1x/
Linux. Чтобы зто продемонстрировать, вот вам краткий список некоторых базовых
возможностей, обеспечиваемых .NEТ.
На основе информации этого списка вы. вероятно. уже сами пришли к заклю
чению. что платформа .NEТ не имеет ничего общего с СОМ (за исключением того.
что оба зти каркаса разработки приложений исходят из MIcrosoft). Фактически
единственным способом взаимодействия типов .NEТ и СОМ оказывается исполь
зование возможностей слоя взаимодействия .
ЗIМIЧIНМI. Описание возможностей слоя взаимодействия .NET (включая Plnvoke) выходит за рам
ки зтой книги. Если вам потребуется подрОбное освещение этого вопроса, обратитесь к моей
книге СОМ and .NEТ /nteroperability (ApreSB, 2002).
Роль языка С#
С учетом того, что приН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
Исходный код
Компилятор с#
С#
.~
Исходный КОД
Компилятор Perl .NEТ
Perl.NEТ IL-инструкции
• и
метаданные
Исходный код
Компилятор Managed С++
Managed С++
•
Рис. 1.2. Все . NEТ -компиляторы генерируют IL- инструкции и метаданные
r
Замечание. Относительно сокращения "IL" здесь уместно сказать несколько дополнительных слов.
В ходе разработки .NET Официальным названием для IL было Мiсrоsоft
lintermediate Language
(MSIL). Однако в вышедшей версии .NET зто название было изменено на CIL (Соттоп
Intermediate Language - общий промежуточный язык). Позтому вам следует знать, что в публи
кациях, посвященных .NEТ, сокращения IL, MSIL и CIL обозначают одно и то же. В соответствии
с терминологией, принятой сегодня, в тексте зтой книги используется сокращение CIL.
Одномодульные и многомодульные
компоновочные блоки
Во многих случаях компоновочные блоки .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
па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 {О}.", апз);
, 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Т) .
Преимущества CIL
Вы можете спросить, зачем компилировать исходный код в CIL, а не прямо в
набор специальных системных команд. Одним из преимуществ этого является ин
теграция языков, поскольку вы уже убедились, что все компиляторы .NEТ выда
ют приблизительно одинаковые наборы CIL-инстрУКЦИЙ . Поэтому все языки MOryт
взаимодействовать в рамках четко обозначенной двоичной Марены".
Кроме того, поскольку CIL демонстрирует независимость от платформы, каркас
.NEТ Framework тоже оказывается независимым от платформы, обеспечивал то, к
чему так привыкли разработчики J ava (единую базу программного кода. способно
го работать во многих операционных системах). Фактически уже имеется между-
r
Глава 1. Философия .NET 57
народный стандарт для языка С#, а значительная часть платформы .NEТ реализо
вана для множества операционных систем, отличных от Windows (более подробная
информация об этом имеется в конце главы). Но, в отличие от Java, .NEТ позволяет
строить приложения, используя язык вашего предпочтения.
TypeDef #2 (02000003)
.assembly CSharpCa1culator
{
r
.modu1e CSharpCalcu1ator.exe
.imagebase ОхО0400000
.subsystem ОхОООООООЗ
.fi1e a1ignment 512
.corf1ags ОхОООООООl
По сути, этот манифест содержит указания на внешние компоновочные бло
ки, необходимые для CSharpCa1culator.exe (для этого используется директива
.assembly extern), а также различные характеристики самого компоновочного
блока (номер версии, имя модуля и т.д.).
Напомним, что crs (общая система тшIOВ) - это формальное описание того, как
должны определяться типы, подходящие для использования в среде CLR. Обычно
внутренние механизмы CТS важны только тем, кто создает средства разработки
и/или строит компиляторы для платформы .NEТ. Но для любого программиста
.NEТ важно знать, как работать с пятью типами, определяемыми спецификациями
CТS для выбранного разработчиком языка программирования. Ниже предлагается
краткий обзор соответствующих вопросов.
Тип класса
Любой язык, совместимый с .NEТ, поддерживает, как минимум, тип к:ласса. ко
торый является "краеугольным камнем" объектно-ориентированного программи
рования (ООП). Класс может состоять из любого числа членов (таких, как свойства,
методы и события) и элементов данных (таких, как поля). В С# классы объявляют
ся с помощью ключевого слова class.
// тип к.nacca Cjf.
public c1ass Calc
{
public int Add(int х, int у)
{ return х + у; }
Тип структуры
Понятие структуры в CТS также формализовано. Если вы знаете С, вам будет
приятно узнать, что зти пользовательские типы "выжили" и в мире .NEТ (хотя вну
тренне они ведут себя немного по-иному). Упрощенно говоря, структура- это
"облегченный" тип класса с семантикой на базе значений. Более подробная инфор
мация о структурах предлагается в главе 3. Обычно структуры лучше всего под
ходят для моделирования геометрических и математических данных, и в С# для
создания структур используется ключевое слово s t r u с t.
Тип интерфейса
Инmeрфейс- это именованная коллекция определений абстрактных членов,
которая может поддерживаться (т.е. реализовьmаться) данным классом или струн
турой. В отличие от модели СОМ, интерфейсы .NEТ не являются производными
одного общего базового интерфейса, такого как IUnknown. В С# типы интерфейса
определяются с помощью ключевого слова interface, например:
// тип ИИ'1'8рфейса С*.
public interface IDraw
(
void Draw () ;
Сами по себе интерфейсы не очень полезны. Однако, когда класс или струн
тура реализуют данный интерфейс своим собственным уникальным образом, вы
можете запросить доступ к соответствующим функциональным возможностям, ис
пользуя ссылку на интерфейс в полиморфной форме. Программирование на базе
интерфейсов будет рассматриваться в главе 7.
Тип перечня
Перечень - зто удобная программная конструкция, в которой группируют
ся пары Нимя-значение". Предположим, вы создаете видеоигру, в которой игроку
позволяется выбрать персонажа в одной из трех категорий: Wizard (маг), Fighter
(воин) или Тhief (мошенник) . Вместо того чтобы использовать и отслеживать чис
ловые значения, соответствующие каждой из возможностей, вы можете построить
перечень, используя для этоro ключевое слово епиm.
Тип делегата
Делегат- это .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 у};
Члены типов
Теперь после рассмотрения всех типов, имеющих формальное определение в
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 членов.
Общеязыковые спецификации
Вы. конечно, <!Баете, что разные 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аксис.
блока.
Гарантия С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'.
И~Д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.4. Один компоновочный блок может содержать любое количество пространств имен
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);
Использование ildasm.exe
ЕсJШ вас цугает перспектива освоения всех пространств имен платформы .NEТ,
вспомните о том, что уникадьность любого пространства имен заключается в ТОМ.
что оно содержит типы. некоторым образом семантически связанные между со
бой . Поэтому. например. если вам не нужен интерфейс пользователя для простого
консольного приложения. то смело можете забыть (среди прочих) о пространствах
имен Sуstещ. Windows. Forms и System. Web. Если вы строите приложение для рабо
ты с изображениями, то вам вряд ли понадобятся пространства имен для работы
с базами данных. К тому же. как в случае любой новой бибJШотеки готового про
граммного кода. вы можете учиться по ходу дела.
~ МА 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':~
Просмотр С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~~~
МНЬ1Й :код Сп,. :Конечно, "JТOбьr быть сyne,рзвездой С#,. сов(':ем не о(5язатe.юmo быть
ЭR€пертом по проrраммному K€lд.Y CIL, но ПОНИМЩие е~тахсИCCl CIL 'TWXЫto укре
r:;r:ит'ВЩШJ "мyc1WJIЫ лрогра:мм:ировaшut~,
Раздел 1. Архитектура Описывает общую архитектуру CLI, включая правила CTS и CLS,
а также работу механизма среды выполнения .NEТ
Замечание. Если вы хотите узнать больше о Мопо или 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Т
Р· езюме
Целью Э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 С#
том, что .NEТ Framework 2.0 SDK автоматически устанавливается при установке
VisuaI Studlo 2005 или Visual С# 2005 Ехргевв. поэтому если вы rшанируете уста
новить одну из указанных систем, то загружать и отдельно устанавливать пакет
ЦИИ.
Таблица 2.1. Подкаталоги корневого каталога установки .NET Framework 2.0 SDK
Подкатаnог Описание
'.' самыы очевИДf'IЫМ ЯIiJlЯетспто, что ~Ы можете цросто не :иметь Vlsual Sttidlo
2005~
Полезным "цобочным эффектом" раБ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щвой странн.-
Если все было сделано правильно. вы должны увидеть список опций настройки.
ПО)1ДеРЖJШаемых компиляторОМ С#.
Замечание. В списке аргументов командной строки для любого средства разработки . NEТ в каче
стве разделителя можно использовать - или I (например, csc -? или csc I?) .
Совет. Теперь вы знаете, как вручную настроить свою машину, но есть и более КОРОТКИЙ nyn,.
Среда .NEТ Framework 2.0 SDK предлагает уже сконфигурированное командное окно, рас
познающее все утилиты команДНОЙ строки .NEТ Используя кнопку Пуск, выберите из меню
Все Программы~Мiсгоsоft .NET Framework SDK v2.0 и активизируйте строку SDK Command
Prompt (Командная строка SDK).
ОnциSl Onис~ние'
Здесь не указан нв:В:о флаг 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;>ке).
<:;3:'с Test_A.pp. сs
ПrМIeт ...
class HelloMessage
{
public vo:Ld speak (:)
{
Мessag'eBox. S,how ("I1ривет ... ") ;
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еВох. $ЬОМ, ( "Приве~ •.. ") ;
замечанке. Флаг /reference Я'J;lЛЯЕПСЯ J<YМYЛЯТИВНЫМ . Н6за8ИС~МО ,от того, где вы укажете
внешние ~омnрнов0чныБл\).I(ии (до,. :ПОDле ИЛL1 8~УТРИ о,-вет.ного файла). результатом будет
обьедйненwв- всех ССЬiJIОХ.
в табл. 2.3 ПOlсаззны некоторые (но. конечно же. не все) флаги с указанием их
сокращенных форм. раcnознаваемые отладчиком cordbg. ехе в сеансе отладки.
Флаг Описание
,1
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 ~]
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
(
ПОАключение 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И\сзс.ехе.
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. Установка параметров команды Аил
Run ~,
~
"--.а:
t;i;p-;';~~-:---~--- -~=-~_ ~
C~ .. ~_~_._._.'::~_-'- ]
. .
1n(jS1!*Ior.. ~\TooctP!ldT~ --~ _О]
D~~ 0CII*W~
Dao.oos ......... ..,_ OfQ1МOnUod
, ]
еж
Компоновка.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).
i'iindow. Se<vice
location:E\~';";.'~
-.< -_.
s~~\~~;J$eпl~ТЕRтЕсff~~"i~j CJ
......... ...... . _ ... ..
Г"" ~
Возможности 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о:
• наличие ДИ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 блоков);
. ~Ye
ок
G3 GII MySOWnApp
Gj. lfjJ MySOWnдt<p
s (}~
'·-0
Е! .~ М..nA>nn
• Мiin($tmQШ
;r,. Jri!i8iZ!!C"""""""t.(}
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'~ Ш-
~ i ЩI~ ~ 1ii\i
~~-----
Default
F.....
Тор. L.ft
. I . . . r.... Red
'. Backgrnundlmag. D (П""")
. Clu.esv.Hd<!tiorI TГU!!
. , С оntextМ.nо (попе)
Cursor Default
Компоновка .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ГО семейства.
За~ечанм~. Во время подготовки ,ЭТОЙ tcМИГ:1-1 к печати семейство продуктов Expгess I! В\tIдe бета
верСИЙ npeдnага:пось соверще!1I'!О б!аСnлатно_
Компоновка.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.
Чеетно говоря. 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И,
,. 'гI
s Щ'~_
~. ~~Infi""s
~ ..» I\.~tnce
''!iIБ~~
-Q ~I!!m . o..~
.~ SffiI"I\.XmI
'ii\\lP~_.a
Обратите внимание на то, что п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ОНОООЧНЫЙ блок
.---=:=-=.::=::;
-- - -·c~·- . - - -- ~_----
о -._,-.-'-----. "-- ---.---
- -~'-
'
,i дpp/ication
:-- ~ -- -'--- l
i~ l
, bld Events !,
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~ , .- -- - - -
ИнтеГРИРО'В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 придат:ь своему
~\т'~~'I~~~'
<Seiord1>
в параметр)
сlааз Е'з::оgram
[
~;'tatic void Z,Ia:l:n (stringI ] args')
I
Conf.i.gureClJI () ;
j J Ожидание наж.аТИJiJ 1ШавИЩИ для '3.аll~рще!iИЯ работ~.
C;onsole. ReadliIle () ;
}
работки программ.
для работы с этими возможностями 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'"
e l"l~
о Delegall!
4-lnheritoInce
*'- A~1iO(1
tAc~
Рис. 2.25. Вставка нового класса с помощью визуальных средств Class Designeг
Если теперь взглянуть на определение С#-класса Car. вы увидите. что оно соот
ветствующим образом обновлено.
Добавьте в Ш,НО диаграммы 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п
~by;
~{ 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~/
Дополнительные средства
р'азработки . 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-адРеса. до которым можно найти дополни
тельную информацию.
,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рогрвммного кода
Резюме
Как видите, в ваше полное распоряжение предоставлено множество новых
игрушек! Целью этой главы было описание самых популярных средств создания
программ на языке С#. которые могут ускорить процесс разработки. Обсуждение
началось с описания того. как сгенерировать компоновочный блок .NEТ, не имея
ничего. кроме бесплатного КОМIIИЛЯтора С# и программы Блокнот. Затем мы рас
смотрели приложение ThxtPad и выяснили, как настроить этот инструмент на ре
дактирование и компиляцию файлов * .св с npогрaммнblМ кодом.
Были также рассмотрены три интегрированные среды разработки с более ши
рокими возможностями: сначала SharpDevelop с открытым исходным кодом , затем
V1sual С# 2005 Express и, НaIюнец. Visual Stud10 2005 от Мicrosoft. Эта глава толь
ко коснулась всего богатства функциональных воэможностей каждого из этих ин
струментов, чтобы вы могли приступить к самостоятельному изучению выбранной
вами среды разработки. В завершение бьш рассмотрен ряд инструментов разра
ботки .NEТ с открытым исходным IЮДОМ, которые могут преД1IOЖИТЬ разработчику
дополнительные возможности.
ЧАСТЬ 11
языIK
программирования С#
!
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 С#
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 Т,Д,).
Замечание, МеТ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.
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] ) ;
Вмест.о {:та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'.
J.
'.- .
"
i~
1!!ui6 ,SIIn,AriIart ~--"~-- ~~ /"
I ~t;;~_ 9 ---...
~_...........
''~~:i
, 1
ГD!tJWg J О Sl8'ted!:mlt~ ·Г
! ' - - -- - -- - - - ' ~)
ъ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
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 () ;
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 (') :
.. ,
}
Роль КО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.шР ....} ;
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.Ю.•
Ут-ечка пам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
объекты.
class HelloClass
r
pulHic static int Маiл (.st.rl.ng [] ад:чв)
[
Fle1l0Class сl ;: new HelloCl азз О ;
class HelloApp
Класс 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
...
int thelnt = 90;
double theDouble = 9.99;
Ьооl theBool = true:
СиМItОIlW фcp.ta
Onмcaнмe
пtpOltани" СТРО·
Доступность членов
Прежде чем двигаться дальше. мы должны обсудить BOnpOC доступности. ИЛИ
"видимости" членов. Члены (методы, поля. конструкторы и т.д.) данного класса или
структуры должны указать свой уровень доступности. Если член определяется без
указания ключевого слова, характеризующего ДОС1YПRость. этот член по умолча
Модкфмкат()р
Описшntе
доступности С#
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 блоке
/1 С>цtщиД()C1rymIOсll.'И члеНiОВ.
сlазз БоmeСlаsв
11 Дoc'!!yц~ Вti!ЗД~.
publi с ~юid РЬЬ} i,~МetJlod () ! J
Доступность типов
1)шы (классы. интерфейсы. cтpYК'I)'Pbl, перечни и делегаты) также могут ис
пользовать модификаторы доступности. но только pl1blic или internal. Когда вы
создаете общедоступный тип (public). то гарантируете, что он будет доступным
для других типов l(aк в текущем компоновочном блоке. так и во внешних компо
новочных блоках. Это может оказаться полезным только тогда, когда вы создаете
библиотеlty ирограммного I<ода (см. главу 11). но здесь мы можем привести пример
использования этого модификатора доступности.
Замечание. В таве 4 будет говориться о вложенных типах. Вы узнаете, что вложенные типы тоже
могут быть объявлены, как приватные.
Глава 3, O(;!,loabl языка С,# 131
Значения, назнача,емые
переменным по умолчанию
ЧЛ!lliaМ-перемеЕ:НЬtм :классов автоматичесви ЦРU~1JaИВaЮТСj'l ТJQдх.одяпurе аца,
т.regин. лрецусмотренныe ПО умолчанию. 3ТН 8начения ДдН ~oгo типа дaIщых.
СВОИ, но правила их выбора ДОС1:'ЗТ(!}ЧНО просты:
Синтаксисинициаnизациичnенов-переменных
ТИпы класса обычно имеют множество членов-переменных (также называемых
полями). Если в классе можно определять множество конструкторов, то может воз
никнуть не СЛИШRом радующая npограммиста необходимость многократной запи
си одного и того же программного кода инициализации для каждой новой реализа
ции конструктора. Это ВПОJШе реально. например. в том случае. когда вы не хотите
принимать значение члена. предусмотренное по умолчанию. Так. чтобы член-пе
ременная (myInt) целочисленного типа всегда инициализировался значением 9. вы
можете записать следующее.
Определение констант
Итах. вы знаете, Щ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 экземпляра.
с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. Язык программирования С#
Ссылки на константы
Если нужно соСлаТься на константу. определенную внешним типом. вы должны
добавить префикс имени типа (например, ConstData.Truth). ПОСIЮЛЬКУ поля-кон
станты являются неявн.о сmаmuческu.мu. Однако при ссылке на KOHCТaнry. опреде
ленную в рамках текущего типа (или в рамках текущего члена). указывать префикс
имени типа не требуется. Чтобы пояснить это, рассмотрим следующий класс.
class Program
(
public const string BestNhlTeam = "Wild";
static void Main(string[] args)
Обратите внимание на то, что д;ля доступа к константам класса ConstData не
обходимо Уliаэать имя типа. Однако класс Program имеет прямой доступ к констан
те BestNhlTeam. ПОСliОЛЬКУ она была определена в пределах собственной области
видимости класса. Константа LocalFixedVal11e, определенная в Main (), конечно
же, должна быть доступной толыio ИЗ метода Main ().
Поля, доступные 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,) ;
1
136 Часть 11. Язык программирования С#
Поля. доступные только для чтения, отличаются от констант еще и тем. что
таким полям можно присваивать значения в контексте конструктора. Это может
оказаться очень полезным тогда. когда значение. которое нужно присвоить доc-ryn
class Employee
(
public readonly stril1g SSN;
public Employee{string empSSN)
(
SSN = empSSN;
Здесь SSN является значением readonly (только для чтения). поэтому любая по
пытка изменить это значение вне конструктора приведет к ошибке компиляции.
Статические методы
~С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) ] ;
Статические данные
Вдобавок к статическим методам. тип может также определять статические дан
ные (например, член-переменная Random в предыдущем классе Teenager). Следует
понимать. что когда класс определяет нестатические данные, каждый объект дан
ного типа подцерживает приватную копию соответствующего поля. Рассмотрим ,
например, класс. который моделирует депозитный счет.
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'о .их класса
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. Язык программирования С#
Статические конструкторы
Вы уже знаете о том, что конструкторы используются ДЛЯ установки значения
данных типа во время его создания. Если указать присваивание эначения элемен
ту статических данных в рамках конструктора уровня экземпляра. вы обнаружите.
что это значение переустанавливается каждый раз при создании нового объекта!
Например, изменим класс SavingsAccount так.
class SаviпgsАссоuпt
(
public double currBalance;
public static double currlnterestRate;
public SavingsAccount(double balance)
{
currBalan ce = balance;
currInterestRate = 0.04;
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;
Ст'атические к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, для которого нельзя создать эк
земпляр, должен быть совершенно бесполезным. Однако если вы создаете класс,
не содержащий ничего. кроме статических членов и/или констант. то нет никакой
необходимости и в локализации такого класса. Рассмотрим следующий тип.
Модификатор_ып'араметров методов
Методы (и статические. и УР(}IЩ.Я ЭJщeмплiiра) могут исп{ЩЬ.зоватъ параметры.
передаваемые вызывюсщей сторonо.й'. Однако., в О1lIИ'lИе Q']; яекО1'орых друтих яЗы
ков цро.граммиро.вa1lИИ. В С# предлагается Мliржество МDдифи:ка1'ОРОВ naраметрьв.
которые RОЦТР(ЩИРУЮТ способ передачи (ц. возможно, возврата) .аргументов ДЛЯ
дшпtого метода, кaI< n.о.казано в Табл, 3.5.
Модификатор out
Теперь рассмотрим использование параметров out (от output- выходной).
Если метод определен с выходными параметрами , то необходимо назначить этим
параметрам подходящие значения до выхода из метода (если этого не сделать, бу
дет сгенерирована ошибка компиляции).
Ниже для иллюстрации предлагается альтернативный вариант метода Add ( ) ,
использующий С#-модифuкатор out и возвращающий сумму двух целых чисел в
виде выходного параметра (обратите внимание на то, что возвращаемым значени
ем самого метода теперь будет void ).
/ / Выходные параметры задaJD'l'СЯ чnено",
public static void Add(int х, int у, out int ans)
{
ans = х + у;
Этот пример предлагается здесь только для иллюстрации: нет никакой необ
ходимости возвращать значение суммы с помощью выходного параметра. Но сам
модификатор out играет очень важную роль: он позволяет вызывающей стороне
получить МножесТво возвращаемых значений от одного вызова метода.
МодИф'икатор 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ЫИ па;раметрами.
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;
Модификатор params
Нам осталось рассмотреть модификатор params. позволяющий создавать мето
ды, которым можно направить множество однотипных аргументов в виде одного
параметра. Чтобы прояснить суть дела, рассмотрим метод. возвращающий сред
нее для любого числа значений.
Итерационныеконструкции
Все языки программирования предлагают 'конструкции обеспечивающие воз
можность повторения блоков программвого кода, пока не выполнено условие завер
шения повторений. Если у вас есть опыт программирования. то операторы цикла в
С# будут для вас попятными и не должны требовать пространных объяснений.
Глава з. ОСНОВЫ я~ыка с.# 147
в С# обеспечивrotrrся следУЮщие q~rpe итерщщtmные КОНСТРУ'КЦИИ;
• Ц1mл for;
• ЦИЮI foreach/ in;
• ЦИlt.lJ wЬil€';
• 'ЦШUI 00 /:whi 1е.
Цикл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.
J
// ЗД$СЪ веремеНИ&JI ' i ' ие,чос'Ж'уIЦUl,.
Цикл foreach
Кmoчевое слово С'# fO.r-еасh. llОЗВО~IНет повторить 0лредеденпые действия для
всех элементов MCj.~cl!IВa без необходимости ВЫ$JСЛfНИЯ разм~р.ов массива. ВОТ два
ПРJiмера Ис;ПОЛЬЗО:вaI01я f'orea.cn. один ДЛП маСШIВа CTPort, а дpyrdЙ- рдя массива
Цe.iIЬШ ЧИС~ .
Цикл do / while подобен цикпу while. как и цикл whi1e. цикл d o/ whi1e исполь
зуется для выполнения последовательности действий неопределенное число раз.
Разница в том. что цикл d o /wh i1e гарантирует вьmолнение соответствующего бло
ка программного кода как минимум ОДИН раз (простой цикл while может не выпол
ниться ни разу. если условие его окончания окажется неверным с самого начала).
Оператор if/els.e
в отличие от С и С++. оператор if l e He в С# может работать только с булеШ'!I
ми "Выраженидми, а Ве с произвольныыи знаЧ~ЩМR -l. О, Поэтому в операторах
it/el.s'E': обычно исщwьэуют.с'я операЦии С#. дон.аЭанНые в табл . 3.6. чтобы полу
Ч:ИТЬ ОУЮЩ1Lb1;lЬre булевы эRaЧ'еIiИи.
Операция
При мер ~о:n ..зоевИИR ОпиcaJlие
сравнения
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
в данном c.nт-Iae ДЛЯ исполъзова:,rIЩl сваиства Str i ng. Lеп g t t. ЩЖЩ>. изменитЬ
УCJ,Iовие ттс . ЕаЕ показано 1:iЩJtE .
&& Н( (age 3О) && (пате "Fred") ) Условная операция AND (И)
Н( (age (пате "Fred") )
" Н(! myBool)
30) 11 Условная операция
Условная операция
OR
NOT
(ИЛИ)
(НЕ)
Оператор switch
Другой простой конструкцией выбора. предлагаемой в С#. является оператор
switch . как и в других языках типа С. оператор switch позволяет обработать по
ток выполнения про граммы на основе заданного набора вариантов. Например.
следующий метод Main () позволяет печатать строку. зависящую от выбранного
варианта (случай default предназначен для обработки непредусмотренных вари
антов выбора).
switch (п)
(
case 1:
Сопsоlе.WritеLiпе("Отлично! С# - это прекрасный язык.");
break;
саэе 2:
Co n sole.WriteLine("VB .NET: ООП, многозадачность и т.Д. !");
break:
default:
Console. Wri teLine ("Хорошо ... удачи вам с таким выбором! ") ;
break:
Именно это используется в следующем операторе 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итает.е·: ТО),
саЭе "С#":
С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;
((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НИЙ.
Этот пример может не содержать для вас ничего нового. но важно понять. что
,NET-СТРУКТУРbl (как и перечни, которые будут рассмотрены в этой главе позже)
тоже являются типами, характеризуемыми значением, Структуры. в частности,
дают возможность использовать основные преимущества объектно-ориентирован
ного подхода (инкапсуляции) при сохранении эффективности размещения данных
в стеке . Подобно классам, структуры могут использовать конструкторы (с apryмeH
тами) и определять любое число членов.
Все структуры неявно получаются из классаSystem.ValueType. С точки зре
ния фуmщиональности, единственной целью System.ValueType ЯJщяется "пере
определение" вирryaJIЬНЫХ методов System.Obj ect (этот объект будет описан чуть
позже) с целью учета особенностей семантики типов, ЗадаННых знаЧениями. в про
тивоположность ссылочным типам. Методы экземпляра. определенные. с помощью
System,Val ue Type, будут идентичны соответствующим методам System.Object.
// Эт о р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.у);
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. Язык программирования С#
Здесь создается переменн:ая типа Mypoint (с именем рl), которая затем присва
Ивается другой переменной типа MyPoint (р2). Ввиду того, что MyPoint является
типом. характеризуемым значением, в результате в cTeRe будет две копии типа
MyPoint, каждая из которых может обрабатываться независимо одна от другой.
Поэтому. когда изменяется значение р2.х, значение pl.x остается прежним (точно
так же, как в предыдущем примере с целочисленными данными).
Ссылочные типы (классы), наоборот, размещаются в управляемой динамиче
ски распределяемой памяти (managed Ьеар). Эти объекты остаются в памяти до
тех пор, пока сборщик мусора .NEТ не уничтожит их. По умолчанию в результате
npисваивания ссьmочных типов создается новая ссьтка на тот же объект в дина
мичеСRОЙ памяти. для. иллюстрации давайте изменим определеrше типа MyPoint
со структуры на класс.
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Ф,' }
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;
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);
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!?, оач~ ); !
{
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 (! ;
Как видите, значение возраста (age) изменяется. Кажется, такое поведение при
передаче параметра противоречит самому термину ~по значению", Если вы спо
собны изменить состояние получаемого объекта Person, что же все-таки копиру
ется? Ответ здесь следующий: в объект вызьmающей стороны копируется ССЬика.
Поэтому. поскольку метод SелdАРеrsопВуVаluе () и объект вызывающей стороны
указывают на один и тот же объект, можно изменить состояние данных объекта.
Что здесь невозм.ож·но, так это изменить саму ссыJшy так. чтобы она указывала на
другой объект (зто напоминает ситуацию с постоянными указателями в С++).
Тиn~ харanеризуемыJi
BOnPQc
ЗН8че",МtЩ
Мржет ли тип бъrrь б~овым ;цтl Нет. Типы. хараt(теризуемые . рР., Если тип .не ИЗОl1I-1РQ.Ван,
Щ)у.гих типов? ЭNаЧ8l'tиями, вcsща lII.ЗоJiи " он' может быть базовым iЦЛi1
раваны и не могут бt:llТЬ РаС друrиx ТИП09
ширены
1
-
160 Часть 11 . Язык программирования С#
менты)
Когда переменные данного типа Когда они Оl<азываютсЯ вне Когда для управляемой дина
прекращают свое существование? контекста определения мической памяти выполняет
ся сборка мусора
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
c lass Program
(
static void Maln(string[] args)
Замечание. !3 С# 2' Р flотери ГlРОИ~ВОДИ1ельн~с"и из-за пр~едения " с€)ылочному' типу И аосCi.тэ
нов:tlения !ltз объектного 06раза Можно нивелvrроооть ПуТем испопъзоваНИII 0606щеN",Й (gene-
rics), к,оторые бvдут pacqMorpeHbI в главе 10.
$truct MyPb:LFlt
{
public iл .t х, у:
-
164 Часть 11. Язык программирования С#
MyPoint р;
р.Х = 10;
р.у = 20;
UseBoxedМyPoint(p);
При попытке получить доступ R полю данных MyPoint возникнет ошибка ком
пиляции. поскольку метод предполагает. что вы действуете на строго типизован
ный System.Object.
static void UseBoxedMyPoint(object о)
{
// ОШибха! System.Object не имеет чnеНQв-перемевных
// с именами 'х' и 'у'.
Console.WriteLine("(OI, (11", О.Х, о.у);
I
else
Console.WriteLine("Bbl прислали не MyPoint.");
/ / ДOJIЬ$овaorеiiIЬОХИЙ' ПЕ\речень.
enurn ЕтрТуре
j
Manager, /1 = о
Gxunt, 1I :;1
Cont.r", ct. о!' , '} == 2
ур
11 =3
!
Matla:ge'I' = 10~,
Grunt, 11 == 103
COh:,tract6r, /1 == 104
\rlP 11 = 105
Замечание. ПРi1 ссылке на значение перечня всегда следует добавлять префикс имени перечня
(например, использовать ЕmрТуре . Grl.lnt, а не просто Grunt).
Чnем Оп"'самме
GеtNаще() Возвращает ИМ~ (И1lи МВООИ8 ИМ81'1) дЛЯ константы с yкaМJ,HHЫM значе"
'GHNames' () ~ием
I.$Def ir1e'd ( ) Возарщдает прlIIЗ'NВК существовакl'Il'I в ,lJЩIНQМ Гlepe 1 1He кi:J1:ICТW1ТbI с УII:Э
заННbiМ 3НВ\l6Нием
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 . Язык программирования С#
ниями . например:
Мастер-класс: System.Object
Совет. СледУЮЩИЙ обзор System.Object предполагает, что вы знакомы с понятиям и виртуаль
ного метода и переопределения методов. Если мир ООП ДЛЯ вас является новым, вы можете
вернуться k. этому разделу после изучения материала главы 4.
...
170 Часть 11. Язык программирования С#
Метод экзеМПЛllра
Описание
клаоса Object
Na рис. 3.17 покasaн вариаит BЬJВOдa. полученного при TeLTOBCIМ запуске :upo-
граМмы.
имеет тип Person. однако здесь не создается новый экземпляр класса Person. а
присваивается fred переменной р2. Таким образом. и fred, и р2, а также пере
менная о (типа object. которая была добавлена для полноты картины) указывают
на один и тот же объект в памяти. По этой причине тест на тождественность будет
успеIIIны •.
Переопределение элементов
System.Object, заданных по умолчанию
Хотя заданное по умолчанию поведение System.Object может оказаться вполне
приемлемым в большинстве случаев. вполне обычным для создаваемых вами типов
будет переопределение некоторых из унаследованных методов. В главе 4 предлага
ется подробный анализ возможностей ООП в рамках С#. но, по сути, nEреоnpеделе
ние - это изменение поведения наследуемого виртуального члена в npоизвоДНом
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();
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Л)С);
Эдесь с помощью ключевого слова 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. Язык программирования С#
return false:
Теперь предположим, что у нас есть тип Car (автомобиль). экземпляр которого
мы ПОIIЫтаемся передать методу Person .Equals ().
/I A!lТОlllобили ~ это не moди!
Car с = new Car();
Person р = new Person();
p.Equals (с);
// Ой!
Person р = new Person() i
p.Equals (mJll):
if (рЗ.Еquа1s(р4))
Сопsоlе.Wri~еLiпе("-> Состояния рЗ и р4 од и на к овы!");
e1se
Сопsоlе.WritеLiпе("- > Сос тояния р3 и р4 различны!");
С)6ОЗНll1е· Соrnарован-
нне 11 С# НОСТII с c~e
Тип System ...
д .,.азоН мзменеН... Описание
деОЯТИLI~JЫМ раз-
дели.телем
Туре
- String
- Aц~y
I!юб&й,JМh•.
- " Excepti:on ~t.i~Ът·: h--====:::::::::"~____ .....J
. YAlи~~yp~.. '
Явnяeтся .
aтp~,
ИЛИ~~М;
1 .
но нelJcnacCOU.
. '" .
Мultica;stOelegate
...... .
SByte
Кстати. заметим. что :можно создаваТJ> сис_теМНЪJе тцnы ДЗНRЫХ. Иf:1l0ЛЬ3yst аб
солютные имена.
Члены System.Char
Текстовые данные в С# представляются встроенными типами данных string
иchar. Все . NEГ-языки отображают текстовые типы в соответствующие базовые
типы (System.String и System.Char). Оба эти ТИIIа в своей основе используют
Unicode.
тип System.Char обеспечивает широкие функциональные возможности, дале
ко выходящие за рамки простого хранения символьных данных (которые, кста
ти, должны помещаться в одиночные кавычки). Используя статические методы
System.Char. вы можете определить, является ли данный символ цифрой, буквой,
знаком nyнктуации или чем-то иным. Для иллюстрации рассмотрим следующий
фрагмент программного кода.
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.
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
набор операт.оров.
Член Оомса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~М регистре
a~ъ..мы Cd:щаем тип s.tri пч, аызьmающий методы' CGHlta iпs О . Eepl.ace (,) и
Iпsеrt (). Соотвeтr;ТВУЮЩИ:Й В:ЫВОД показЭ1:I на рис. 321_
Вы должны учесть ТО. что хотя 5tring и является ссъmочным типом. операции
равенства инеравенства (== и ! =) предполагают сравнение значений со строковы
ми объектами, а не областей памяти, на которые они ссьmаются. Поэтому следУЮ
щее сравнение в результате дает true:
5tring 51 = "Не110 ";
5tring 52 = "Не110 ";
COn501e,WriteLine("51 == 52: (Ol", 51 == 52);
/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) );
Управляющие последовательности
как и в других языках, подобных С. строковые литерaльr в С# могут содержать
различные управляющие последовательности. которые интерпретируются как
УправЛllJOщjtя
O"K~aнмe
посnеД08а:rел,"носп.
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
о ченъ
Роль System.Text.StringBuilder
тип зtriпg прекрасно подходит ДЛЯ того. чтобы представлять базовые строко
вые переменные (имя. SSN и т. п . ). но этого может оказаться недостаточно. если вы
создаете протрамму. в КОТОРОЙ активно используются текстовые данные. Причина
кроется в ОДНОЙ очень важной особенности строк в . NEг. значение строки после ее
определения изменить нельзя. Строки в С# неизменяемы .
На первый взгляд. это кажется невероятным. поскольку мы привыкли присваи
вать новые значения строковым переменным. Однако. если про анализировать ме
тодыI Systern .String. вы заметите. что методы. которые. как ка;жется. внутренне
изменяют строку. на самом деле возвращают измененную копию оригинальной
строки. Например. при вызове ToUpp er () для строкового объекта вы не изменяете
буфер существующего строкового объекта. а получаете новый строн:овый объеICТ в
форме символов верхнего регистра.
11s,il)g S:'t·stem.;
4.siлg SY$t,em,Тe~ti !1 Эдесь ) JPfВe11" str.ingВuilder .
stat.icsUing [] G"tStrin.gATray ~)
(
str.ir1ЧjJ thеStr:iЛ;jВ = ! "ПрИвет", "с' т", "GetStringArray" };
,r -et.urn thеStri.ngэ;
На рис. 3.23 показан соответствующий вывод (обратите . что здесь массив имеет
"не ровный край").
1
192 Часть 11. Язык программирования С#
Обратите особое внимание на то. что при вызове метода Clear () ДЛЯ массива
оставшиеся элементы массива не сжимаюТСЯ в меньший массив. Для подвергших
ся очистке элементов просто устанавливаются значения по умолчанию. Если вам
нужен контейнер динамического типа, ПОИIЦите подходящий тип в пространстве
имен System.Collections.
массивах ТaI~ИХ типов. При ПОIIЫТке создать ссьmочный тип (включая строковый)
с разрешением значения nu 11 вы получите ошибку компиляции. Подобно перемен -
ным без разрешения принимать значение nUll, локальным переменным с таким
разрешением тоже должны присваиваться начальные значения.
г.лава З. ОС.НОВЫ языка С# 193
эt. аtiс voi~ Main (Bt.ring[] .args)
{
11 И8С11CQ;JIЬКО ОПР8Д831е~ nO:KВJlЬВJ.D!: or~pв
/I с раsреu!JНЫМИ звачеllИ!QQ!f null.
iл:t? Dullablelnt = 1 О:
do .uыl?? l~l.JllableDoub,J; ~ = 3 .14;
:bool? f!ullableHool = rлй 1;
ch.ar? nulLableChar = la ' ;
;i..n:t? [] аrrауОfNul1аblеIл-ts = I!ew int? [10J;
11 OIIIИбха! Стражи ~CB СOlШО!lИlollCИ ~8ХИ!
s·tring? 5 ' = "QЙ!":
J
СуффИНС ? в Cft Является санра:щIШ1ЮЙ записью ДЛЯ указания создзтъ перемен
нyto СI рукгуры обобщеНного тIШa System.NuJ.lab1e<T>. Мы рассмотрим оооБЩе
нин в Лlаве 1О, а сейчас важно IiOНЯтb то, ч.то тип Sys tem. Nulla1Jle <'Г> предлагает
ряд членав, :кoтnp:ыe .могут использовать все типы с разрешением зиачения null.
Например. используя свойство HasValue или OIIepaцm.o 1=. вы можете nporpaмм
ным nyFем выяснить, содержит ли соответс1f'ВУЮЩая переменная з:вачеЮiе Ilull.
3начение.присвоенное типу с раЗрешением значенйn 1'1t111, можnо получать не ·
посредСтвенно или с помощью св.оЙtт.ва уаlие.
~lазs DatabaseReader
1
11 Пonе ;qаившr с pa~ellleJUffJ. aH"~ n1l111 .
pupl:j..c iпt~ пшnbеriсVаluе:
рuЬН.с bool?' 0001 Vаlщ: = true;
Операция ??
Еще одной особенностью ТИПОВ с разрешением принимать значения n-ull, о ко
торой вам следует знать, является то, L{TO с такими типами можно использовать
появившуюся в С# 2005 специальную операцию, обозначаемую знаком?? Эта
операция позволяет присвоить типу значение, если его текущим значением ока·
зывается null. Для примера предположим. что в том случае. когда значение. воз
врашенное методом GetlntFromDatabase (), оказывается равным null, соответ
ствующему локальному типу int с разрешением значения null нужно присвоить
числовое значецие 100 (конечно, упомянутый метод всегда возврашает null. но я
думаю, вы поймете идею. RОТОРУЮ ИЮIIOстрирует данный пример).
11 shaреsЦю, сз
ц.s iI1g' в)' s ·t вт ;
nащеSРi'lсе ~1'y.sj1..ape'5
I
11 км..с;;с CiZ,"cle.
clAss Circ:le{ .1'" и,н-тер.еСНБlе методы •• , "( )
11 1tпАt:о lIexaqon.
cla5s Hextigbl'll /'" Водее ин!Ге.реС!iые М8'1'РДЫ ••. */ }
II~Aco Square.
сlавэ S·gl.lare { Jj Еще более ИiI.~·ересkЫе ме:то,цы. " *1
1/ c.i.x~le. са
llэiпg Sysr.erol
лamеsрас:е МySMp8B
t
11 JCnaсс Cirel •.
сlавв Circle( }
}
11 hex.gon. св
usiпg- .system;
na:m6эрасе Иу'Shареs
{
11 Ьаос, R~pn.
сlазs ;rе;jjа~н:ю I J
}
1/ squait"e .СВ
using Буэtещ;
namespace МyShapss
t
11 I(.nacc Squu•.
cla$s StГJare { '}
}
1
196 Часть 11. Язык программирования С#
Вы уже знаете. что в том случае. когда одному пространству имен требуют
ся объекты из друтого пространства имен, следУет использовать ключевое слово
using.
/ / ИCnOJIЪsование '1'ИnОВ из простраиС'1'Ва имен МyShapes .
using System;
using MyShapes;
паmеsрасе МуАрр
{
class ShapeTester
(
static void Mainlstring[] args)
(
Hexagon h = new Hexagon();
Circle с = new Circle();
Square s = new Square();
Еc.nи обновить SrlapeTe.ster, как покашшо ниже. вы полyqите цедый рад со
общений об ошибках .IЩМПИJlИЦlЩ. ПЬСКО.iIЬJo/ два пространсmа имен определяют
i"ИПЫ с одинaщmъnvm н:азВ8..НИЩQi.
11 ~ec!l!80 вео;цаозначвоС'1!ей!
\1's ing S.ystem:
using MyShapes;
u'Sing Иу3 'DShаре's;
n ame:space МуАрр
1
elass S-hареТеstег
j
198 Часть 11. Язык программирования С#
Использование псевдонимов
Ключевое слово С# using можно также использовать ДЛЯ создания псевдонимов
абсолютных имен типов. После создания псевдонима вы получаете возможность
использовать его как ярлык. который будет заменен полным именем типа во время
компиляции. Например:
us ing Sуstеш;
using MyShapes;
using My3DShapes;
11 Ликаи~ациR иеоднозиачнос~и с помощью псевдоника.
using The3DRexagon = My3DShapes.Hexagon;
namespace МуАрр
{
class ShapeTester
{
static void Main(string[] args)
{
11 На самок дenе здесь создае~СR ~Иn МуЗDShареs. Hexaqon.
ТhеЗDНехаgоп h2 = new The3DHexagon();
пашеsрасе МуАрр
{
class ShapeTester
{
static void Main(string[] args)
{
МyAlias.Binary Formatter Ь = new МyAlias.B i nary~ormatter();
ЗамеЧaJ.Illle. Теперь 1:1 С# предnагается и механизм разрешеt'l/llЯ КОl'lфЛИl(.Тоа' дrlf1 OдlllHilKOBb н.азван
lil:!IX прострвн()тв имен, OCHOBrJ,f.lHblt1 на ИСПОЛЬЗDвании спецификатора' псевдонима ПРОСТJDан
ОТВВ' име/-l (: :) и ·глобалыlОЙ" mErrKI-I. К счастью, указаНl:tы.Й ~n КОЛnИЭИМ возни~ает I1'CKlIiO'-Iи
~ПI;IН() редко. ЕсГlИ ваМ требуется ДОПОЩlИтЩ1ЬН8.я ИНф('Jрмаци.я по ,. ЭтоЙ теме, hрочитайте маю
статыо ·Workin.g With the С# 2.0 Command Line Compiler!l (Работа с КОМПИllfIТQРОМ КОМfllJДiiOЙ
СТрОКИ. с.# 2. 0), .которую МOJI(tfQ найти На ·страницах http://msdn . microsoft. COlI\,
муЗЬSЬареs., можно цзменять :ваш программныИ !Сод -так, Katt nОJЩЗaНО ЩlЖе.
class Hexagon{ )
11 Тре~еРJWЙJU1асс Square.
class Square ( )
С учетом того. что теперь пространство имен My3DShapes вложено в рамки кор
невого пространства имен Chapter3, вы должны изменить вид всех соответствую
щих операторов, использующих директиву using и псевдонимы типов.
using Chapter3.My3DShapes;
using The3DHexagon = Chapter3.My3DShapes.Hexagon;
Резюме
в ЭТОЙ (ДОВОЛЬНО ДЛШll-ЮЙ) главе оfkу:ждалисъ самЫе разные acпel\ты яэьma: про
граммиравания С# я zша.формы.'NЦ Б центре вниМания бы.ли КОНСТРУКЦИIJ, КО
торые наиболее qacтo ИСПОJIЬЗyЮТщr В IIJ?ИЛЬжениях и которые могут понадобитъс:я
вам при СОЗ)iании 1'aI<ИХ fiPИJlожещШ.
Вы могли убедитьCJL ч.то вее Щ:IYтрeюmе типы данных в С# соотвe:t'C'DJyЮТ Qпре
делеННЬ1li.r типам из пространства Иl\1ен SysteiIl. Каждый такой ~СЙ:ltfеМlIЫЙ" 'ГЯи
Прeд.i1агает набор член:ов, с ПОМОЩ~ которых npограммныии средс:rзами мm:кЩ)
ВblЯОНИТЬ диапазон изменеНИJl' TJЦIa. БЫЛИ: такЖе рассмотрены особенности 00-
строеiПtЯ1'ИПОl\ .lШaсса в С#, различные правила передачи параметIЮВ. изучеНl;il
ТИПЫ. хаpakТeризуемые вначе;щщми. и ссылочные ТИПЫ. атаиже вьшснена роль
МQгущ.ествеlUiОГО System.Cbject.
Кроме ТОГО. в D1ЩJе обсyждaJШРЬ :возмоЖНости среды CLR, ttОЗВQляюnnrе иcrrощ.
зовать объектно-ориентирщщнный ПОдхОД с оБЩИМИ npограммны.м:и JWHCТPYКrw
ЯЮI. т"зJtliМ}) lЦitH массивы, строки. CтpYJa'YPbl и пере~lНИ.3.десъ же БЫJЩ ра.ссмо
тpeНh1 операции npиведещц:r R объектному типу и ВОССТa1Iовлеюш из объеКП:ЮI'О
Обрава.8тот оростGЙ M~M nО3ВООЯет с J1егкостъю переходить от тшщв, .ха,рах
теризyeмblX :щачен:иями. к соыJд)'-.пIым ТИIIЭ.м И обратно. Накойen. была ра~ирыта
рФIЬ ТИПОВ данных с раэрешедие.м npпни.Ма:IЪ значение null и nокв:аано. :КЩС: стро
"и.тh nолъзавательоtЩе пространства .имен.
1
I
rЛАВА 4
Язьш С# 2.0
и объектно-
и
ориентироваННЬIИ
ПОДХОД
Тип клаоса в С#
Если вы имеете опыт создания об"ЬeJ{Т()В :в p~ ка1шго-то другого язьща про~
:rpaммцрования. ТО, несомиеJ-JШ~, знаете 9 роли оцределе:tnlЙ массов. Формально
говоря, юrзсс- это оцредедeнRЫЙ ПОЛЬЗОВЗ:t'елем тид (User-Defined Туре- ПОТ).
который скомпонован из по.цеЙ дщffiых (ИНОrдз Raэъцшемых щ!'~нaмu'1lt?ремеюtы
ми) и функций (часто вызываемых .меmодWlЩ), возд~.iiствующих на ЭтИ .данные.
Мщ)жество ЦОllей даиных в СОВОRYUности IIреДСТаБ:rщет ~(;ОСТО1IFLИе~ Эlсземnля:ра:
КJЩсса.
204 ч,sIl:ТЬ 11" Я3ыlo: I1Р[Jtр.аjlillМJt[JО8~Нl!.Я с#
~fiI'Ik1'j
n,~y
i" eropID
iI' 1iI1Nг1'l'''~
Ь /Ii'IeIh:d$
• blspЩStiat5
.~
Вcnoмнн:re из rnlillы 3, >ПО масСы R о#. МOr.YТ. О.IIpt"дeлmъ l:ooбo«f. "'lИ'CЩ) iUiJн.cmp1J"~
mopйB- м'о сшщиалънЫе MeтQДjloi. :класса. DбесПечйВаЮщие.nOJI:ЫJ@, вЭ.Телю of;l1:!~tml
ItpiЭС'Ю)'Ю возмо.жность .!WЗдaНmI эtt3~ давнШ"о ЮIaсса с . 3aдa:Jmbl:М поведеJЩ1-
БМ. ftaж:ды:й нлаrn.' В Cff И3Н1IЧa.IIЫm обоопечиваетса mЖ!Л!р.~ ~ШIkЬЩ по
УМDмmшю~ RО'I"ор1ilЙ I10 сщределе'.НИЮ .юшОI,'Дii! не ш,оfе.е'Г аргумеюш. В CДO~
}( H01icтpynropy:,. заданному по умOJГ'mIШю. моЖи.э опредeJlИll'Ъ~ое 'ЧйСЛQ пфiь;ю
ват.e3I'ЬCЮfX KOI-lСТРУИТOf\!ОВ.
дпя наЧ<iЛa мы определим пa.m:y. первую мОАИФпацв;ю R.!l8ot.a Emp.loye,;;; (по
мере Й3,}'ЧJfИiИЯ мат.ерlimла ца:1l'miIЙ гл.авы 'МlOI !!iyдeM .Добавлять в Э'11О'Г .RltШJС Ёl'0выe
фушщиовam.вьre 'ВОЗМОЖ1Ю<..-тиt
p)lbliC Employee{) {
Перегрузка методов
Подобно другим объектно-ориентированным языкам, язык С# позволяет типу
n.eрегружать ero методы. IЪворя простыми словами. когда класс имеет несколь
ко членов с одинаковыми именами, отличаюIЦИXСЯ только числом (или типом) па
раметров. соответствующий член называют n.eрегружен.ным. В классе Employee
перегруженным является конструктор класса, поскольку предложены два опреде
11 Переrpужеииwе ItOHC~YJtTOplol.
public Employee() { }
public Employee(string fullName, int empID, float currPay) { ... }
.Б дalЩОМ случае Fie'Г неоБХQДИМОСТИ ЯВНD добавлять црефикс trJts Е именам Ч1Jе
I1o,n,nepf:jMeНВ:ЫXEm:ployee. потому 'По RОНф.ликт имен y~~e исRJIЮЧен. КоМПИЛНl'ор
м.~eT самостОя'гe.JlЬШ> ВЬ1fIf:Нi>пъ обла(:ти J;tИДl<JМОС'ГИ ИСЦОJTh'Э)'емых членов-uере
меННl5IХ, и Б ЭТОЙ с'И:!уации trJi s назъmaIO'Г неяен:ь,!М: есди юrас:с ссЫлается на спои
собствеДНЫfl поля данных. и членьу-перемевные (6е& КЗ!RИХ' бы то ни было неодно
значвmстеЙ). то tЮ.'3 подразумеnaетея. Тcuщм Qбразом. Црeдыцy:щasl лопша кон
структора фуНкционально идентична с~дующеЙ.
Замечание. Статические члены типа не могут использовать ключевое слово t hi s в контексте ме
тода . В этом есть смысл, поскольку статические члены-функции действуют на уровне класса
(а не объекта). На уровне класса нет this!
JI ЕCnI!l ПOJ]~зоаа .... еnь Вызоае .... э ....о .... КонструК ....ор, .... 0
/ / аереда'1'Ь ВЫЗОВ версии с треllR арryмен.... ами.
public Employee(string fullName)
: this(fullName, IDGenerator.GetNewEmpID(), O.OF} ( )
СледУет понимать. что использование ключевого слова this для передачи вызо
вов конструктора не является обязательным. Однано при использовании этого под
хода вы получаете более удобное и более краткое определение класса. Фантичесни.
используя этот подход. вы можете упростить свои программистскае задачи.
r Глава 4. ЯЗЫК С# 2.0 и объеКТНО-ОjJм~тир()ааI'lНЫЙ f1I,IAxoA209
с учетом тота. qTO наnr. К.IЩСС Щrnрl0у!'.!е Oupеделлет два опфытых метода
(Giv:eHCJnus О 1!1 Displ <.\yStats ()). M;ы имеем ilозможноCТh взайМQдействоваТJ;> с QT-
крытым интерфейсом 7Щ(. lСЗК ПOJC'<\щшо ниже.
~CJm: БЪШОЛНИТh это приломсение в том его COCTO~, 11 нотором OН('J находитсл
сейчас. вы ДОЛЖНЫ получить вывод. ПОдобный пока:ЗaJЦ;фму яа рис. 4.2.
На этот момеш у иао имеется очеНЬ простой тип класс:'! с м:инималъным откры
тым интерфdiСОы. П€ред тем как двиra.тьcя дальше ~ более слажным примеРШll,
дЩi.ВЙТе потратим HeROTopoe Вр6МЯ: на обсуЖдeнJlе ПР1ЩЦИl10В объектно-ори.енти
po:вaa:нoro про.rpаммИр.ования (paCCMOTPeJ-ше 'ГИДа Ещрlоуее мы продomким He).fiIO-
Т'О позже).
21 О Часть 11. Язык программирования С#
Принципыобъектно-ориентированного
программирования
Инкапсуляция
Первым принципом ООП является uн.кancуляцuя. По сути. она означает возмож
ность скрыть средствами языка несущественные детали реализации от пользова
НаСl1едоааИJJlе
СлеАУЮЩИМ. ДРИЩЩJOМ, оап ЯБЛЯетсg НI1CЛВдован.ие. озtIaчающ~е способносТЬ
tIЗ'ЬШа обеспе'чить ПОСТроение ,Qпределеmm новых юrассоn на ОСНОЕе определений
существyюD:l:Щ( RJТЗССО:В. В сущности. наследование позволнет расширить возмож
ности ДОllеДеНИR бааооого ЮIасеа (называемого, таюке родumeщ,скuм классоМ) с
помощью достроени.я поДШIaсса (иааываемого npoщоодны.м IqЩCGQМ или дочернttМ.
It1laCCOM). насл~д~ющего функциональные возм:ожцости pOДWТe.JlЪeKOT'O JtНacca. :На
рис. 4.3 ИJ1JIЮсrpируется отношение поДЧЮIeIOlQСТИ ("l$-а") ДJШ родительских и да
черНИJC Х1шсеов.
Полиморфизм
Третьим принципом ооп является полиморфизм. Он характеризует способ
ность языка одинаково интерпретировать родственные объекты. Эта особенность
объектно-ориентированного языка позволяет базовому классу определить множе
ство членов (формально называемых noлwиорфн.ым. интерфейсом) для всех произ
водных классов. Полиморфный юrrерфейс типа класса строится с помощью опреде
ления произвольного числа виртуал.Ы-iblX, или абсmpактl-iЫХ членов. 8ИРТУarIЬНЫЙ
член можн.о изменить (или. говоря более формально, переопределить) в произво
дном классе, тогда как абстрактный метод должен. переопределяться. Когда про
иаводные типы переопределяют члены, определенные базовым классом, они, по
существу, переопределяют свой ответ на соответствующий запрос.
Гi13ВЗ 4, :Язык С# 2.0 и об:ьектно-6РI1~НТИРDваНI1IЫЙ подход 213
Чтобы ПРОИ.Jr.iIЮСТРИРовать понлтие ПOJlЩ.'IQрфиам~, снова используем ие.рархию
форм. Предположи:м.. что Масс Shape определил MeтQД Draw (), не имеющий ПАра
метро:а и не :ВОЗВр8ЩaJoЩИЙ ничего. С учетом 1"ОГО, что визуюmэацИл ДЛЯ каждой
фЬрмы оказывается уникалыщЙ. nOJUtJЩССЫ (т!щ"Ие кав Hexagon :и Circle) MOryт
ш:реопредeшrrь еОO'tВете1:nУ:Юиum метод так,:как это требуется ДJIН них (рис. 4.4).
~I
&rэoв btaм() дroя ООi.rЮ8
Cfrole trображэе1 kW.
11 М-н-н-да . ..
static void Main(st~ingrJ args)
(
Book miniNovel = new Book();
miniNovel.numberOfPaqes = 30000000;
/I ЧтаНИв.
рuЪНс stting Ge,t.F'ul.lNama () ,{ return fi:J,l1Name;
J1 МО~фикацик.
paы1cc vэid SеtFullВаще (st:ring п)
j
/1 УДllJ1еlUlе Re~ODYC!t'JQD1x CJtI8OJtOB t!, @, #. $ I %) (
11 аро.ер_а ....~!Ж.ц;шcпI (иnи реrис:тра CМld0J10.')
/I nер.,-ц DpИCJt~ави_.
I'ullNa;me = n;
11 Установха значении.
p.ID = В1;
11 Чтение значении.
Console. Wri teLine (" ID работника: {О) ", р. ID) ;
Console.ReadLine() ;
E.mployee е = пе w, Employee ( ) :
е . т = 81;
3aMeof8Kмe. СТРОГО ГQ8QРЯ, S1РЛЫК val ие в С# является H~ J(I]ючевым словом. а. CJ(ope~" коНте/(С!Т
IiblМключевым СЛОВОМ, предOiaВЛЯIФЩИМ НВRВНЫЙ параметР,1ЩТQРЫЙ исполЬЗУеТСя !'IOnepaTQ-
ре пРИG,lЩиеЗНИJ1 в KO~ITeKcтe ме-года. JIIOnOllb/lyeMoro ДЛЯ устажшки значения свойства. Поэrому
вполне доnyотимо имеТh чле~ы-пеlDемеtНШе и 110кз'лыiеe элемеt-tты ДQHHbD( , с именем уа,1 ие.
.а ' :Str1)Q()
• goUD,tt~
• ~ftImII:~~
• QotJ''e)' \ F\oatЭZС)
.. • ueСSО1:iOlБeщtуNl:rlil:et : 5I:r1n9O
ркс. 4.6, Отр(ijражеf,иеСВ(ЖСТtJ ХХХ В . окрытые методы get _ ХХХ () и set ххх ()
JJреДЦОЛ9ЖИМ теперь., что тИп ЕЛliplоуее иМеет частнъхй член-переме.I:tНy!О с
лмен~м €ropSSN для представления номера социальной страховки работнmщ. Эта
п~ремj:':ННая устанавливаетсв через пара.l\reТP KbНCтpyIC'rOpa. I;J: ]J.11.Я ynpwщеmщ этой
lIерем~ной используется свойство So.cialSecuri t. yWu.rr:be r,
// Добaэnеuе по:q,чеp:telOl иа.ОI'O ПQmIi, npeдC'l'aa~.....ro SS»-I:СоЧ.
public Cl~5S Employee
{
Если бы 'Вы т.a1tЖе опредетmи два метода g~ t soci ,11 SecurityNumDe:r ') и
set _Soci а lSec1Jr:i·tyNumber () , то получили б1>l QOnЩКИ коМIДLJJjщии.
11 СвОЙ;С!L'ВО • С, О'J'Oб~е!L'CJr • .пару ие'1!ОДО8 get._I_et_,
public сlазэ Е:шрlоуее .
{
Замечание. В библиотеках базовых классов .NET всегда отдается предпочтение свойствам типа
(В сравнении с традиционными методами чтения и модификации). Поэтому, чтобы строить
пользовательские типы, которые хорошо интегрируются с матформой .NEт, следует избегать
использования традиционных методов get и set.
в некоторых случаях бывает нужно унаэать свои области видимости для мето
дов get и set. Чтобы сделать это, просто добавьте префикс доступности (в виде
соответствующего ключевого слова) к ключевому слову get или set (при этом об
ласть видимости без yroчнения будет соответствовать области видимости из опре
деления свойства).
Статические свойства
в С# таиже поддерживаются статические cвoЙCmвa. Вспомните из гл"Ввы 3.
что статические члены доc1'yпны 1ia урQJще класса. а Ее Э~ (объента) атп
го класса. Например. цредположим, что тиц Effiployee оцределяет элемент стати
ческих данных, предстввляюП:1ИЙ 1-IЭ.Эщm:ие оргсщизa:цmI. 'в IЩ-WРОЙ тpyдoyc>rp6eu
работнив. Можно определИТЬ стат.иче-щсое С:ВОЙСТ~{) [например. уровня шracса) так.
:как покаэан:о :ниже.
st",tic Employee ()
l
с.ощрапуNаmе '= i' Il'i t ert 'e GI1' TrairJiDg " i
}
L
ГЛа1!S 4. Язык С# 2.0 и обliеКТНQ-ОРl>1еНТI1РОВднныi\ ПОДХОД 223
Общих харав:геристИ1t. которые б:удутnpщ:ущи .QCeM потомхам. ПoдRJШССЫ (1:fаыри
мер. SаlеsРеГSО!1 и Manager) расширяют общие фУШЩИОШ1.ЛРные возможности.
добfIВШIЯ специфичеCIQlе элементы Dове.цеюш.
длл нашего· примера М1iI предположим. что класс Мадаgеr раcmиpнeII' ]:;mpl оуеЕ:.
обеспeчившr. 3aIlI1CЪ числа ОПЦИОНОВ. а ltласс Sа1еSРец•.ОП ПQДЦер}ЩIIЩет информа
цию о числе .продаж. В С# расширение JtlIЭCса задается в оnpеделеиии .{tЩlсса опе
рациt:и, обознача~(JИ двоеточием (:). так ПOJJY'UUO"fCЯ ПРОИЭВQдные тицы класса в
сл.едующем фрагмеНте npограммноro кода.
I
I
; base (fu1J.Nam.e , а.!;е, 8DpID, cu:rrPay r ssn)
крытые методы и свойства. Недостатком. конечно, является то, что при прямом до
ступе производного типа к внутрешшм данным родителя вполне вероятно случай
ное нарушение существующих правил, установлеlпIых в рамках общедоступных
свойств (например, превышение допустимого числа страниц ДЛЯ Цмини-романа") .
Создавая защищеЮ-lЫе члены, вы задаете определенный уровень доверия между
родительским и дочерним классом, поскольку компилятор не сможет обнаружить
нарушения правил, предусмотренных вами для данного типа.
11 ЛOГИJt& ЖОВС1l!pУ1Wора _ ••
1
IIДругие чnеЮI, ••
}
/I ОшИб~а ХОМЦJШ5ЩИЙ!
1"!1ЬЬс оlаэs R,eal1yPTSale,sPeTS()l1 : РТSа.1еsРеж:sоn
! ... 1
Наибооее полезным ШlЮчевое СЛОВО seaied ОItaЗЫВаетсн при СОЭДЭI-IIllI авТОНОМ
НЫХЮIассов утWJИТ. Мас.С Stri.ng. оцределенный в пространстве имен Sу'зtern, на
цриме~ явно изолирован.
Позто'\'Ау 'Вы не сможете со:щать ЦО8ЫЙ ЮJaСС, nPОИЗВйДНЫЙ от 'S Y$tem, 5 t r ing:
/I Снова CШПdбiCа!
public clas5NySt:ring : str.1.t\(j
228 Часть 11. Язык программирования С#
Модель локализации/делегирования
кm< уже отмечалось в этой главе, наследование можно реализовать двумя спосо
бамц. Только что мы исследовали классическое отношение подчиненности ("is-a").
Чтобы завершить обсуждение второго принципа ООП. давайте рассмотрим отно
шение локализации (отношение "has-a". также известное под названием модели
ЛОКQJluзации/делегиРО8Ш-ШЯ). Предположим. что мы создали новый класс, модели
рующий пакет льгот работника.
J
230 Часть 11. Язык программирования С#
• Ввиду того, что вложенный тип является членом класса-контейнера. этот тип
может иметь доступ к приватным членам данного класса .
• Часто вложенный тип играет роль вспомогательного элемента для класса
контейнера, и его использование "внешним миром" не предполагается.
Когда некоторый тип содержит другой тип класса, он может создавать члены
переменные вложецного типа, точно так же, как для любого другого своего эле
мента данных. Но если вы пытаетесь использовать вложенный тип из-за границ
внешнего типа, вы ДОЛЖНЫУТО"IНИIЬ область видимости вложенного типа, указав
его абсолютное имя. изучите следующий пример программного кода.
Ввиду того, qт,o ЭТОТ метод ЛВ;1lЯетс.н ОТ1фЬПbl.М. -ВЫ теперь ~eeтe В@ЭМЩКНОСТЬ
выдmъ премии процавцам и менемкерам (UTaJ.bRe ttpОДaJЩам. занm:ым яеnoлный
рабочий день).
.
Глав'84. Язык С# 2.0 и оDъ,еК1tIO-ОРliент.ирмаiНiЬJЙ П(IJ.дхоД 2ЗЗ
.1
234 Часть 11. ЯЗЫК программирования С#
Абстрактные классы
В данный момент базовый класс Employee скомпонован так, что он может по
ставлять своим потомкам защищенные члены-перемеЮlые, а также два вирryаль
..
, ~ ..
~
->JI' NцmbOpls '1! I\Iu!nbsar...
lI\IItf1DCk
If~'"
~ ""'etla>......
Ь
.
lO\ethIdII
~
: .т; J):~.",e
'.'1=.: Proportll!l
I 51 1'ot1tlolТ>e
I
kb, ~~$
. ...11,...
... :5С"Р< 1:" l 'Q"<I1 .
1=. мab".>ds
"""'DX....
"о ~""Ф90. ,. , V~
namespace Shapes
l
public abstract c la ss Shape
I
// Форме мо_но назначить понятное ИИR.
protected string petName;
// Конструкторы .
publi c Shape () ( petName = "БезИмени" : )
public Shape[string s) { petName = s;}
/ / Draw () lIиртуanен и может БЫ'l'Ь переоцредеnен.
public virtual vo id Draw()
f
Console.WriteLine("Shape.Draw()"):
}
// Circle не переоnpедenяет Draw().
p\Jblic c la s·s Ci rc le : Shape
{
public Circle () { 1
publi c Circle(string пате): base(name) { }
public Hexagon() I }
public Hexagon(string пате): Ьаsе(паmе) { j
public override void Draw ()
i
Сопsоlе.WritеLiпе("ОТОбражение шестиугольника {О}", p etName);
Обратите внимание на то. что класс Shape опредеJIИЛ виртуальный метод с име
нем Dr а w (). Вы только что убедились. что подклассы могут переопределять поведе
ние виртуального метода. используя ключевое слово override (как в случае Itласса
Hexagon). Роль абстрактных методов становится совершенно ясной. если вспом
нить. что подклассам не обязательно перео:пределять виртуальные методы (как
в случае Circle). Таким образом. если вы создадите экземпляры типов Hexagon
и Ci rcle, то обнаружите. что Hexagon "знает", каК правильно отобразить себя.
Однако Ci rcle в этом случае будет "не на шутку озадачен" (рис. 4.11).
Глава 4, ЯIIЫК С# 2'.0 и объепно-о-риеliтирован"ый n'OAXO,Q 237
fI Об'МIП' Сис1е- не neреоnpe;ЦUflИ рliianиз&ЦИlO Dж:а.w (3 6азовоZ'о маСоа.
static vo.id мain (:stIing[] ,a rgs)
{
!:lexagon hex = пеw Hexagon:( "'Seth'" :
hex..Dra ~ ();
Яснр, что ЭТО- не идеа.льный: вариант иерархии форм. ЧТОбы заставить каждьШ
nPQИэ.водныЙ ЩЩСС иметь свой собственRh1Й метод Drew (). мощно за,дать Dr:aw () I
как абстракт~ метед класса Sr!ape. т.е Метод. :который вообще не имеет реa.JIй
ЗIЩJШ,~аданио;й !ТО умолчанию. Заметим, что абстран~е методы могут опреде
ЛЯТЬСЯ толыш ~ абстрaJtТНI:йX классах. Если вы попытаете(JЬ сделать это Б другом
JtЛaссе, то долУ'~ите ошиб~ .нОМПИЛ.!ЩИИ.
/I :В:~ н. 8a,ц&!I!. реа.пиз8ЦИ1О xe!l!oJ\& -D raw (), '1!О zt,Па.сс Circ1:e дomeeв
11 БR'Ro абс~ах'DЮIDI и не дощrсжа'l1Ъ Н~ОСР&ДCIТВ&ИИ3I]D реa.nиsацшо!
рu.ЬНс C'lass Circ le: Shape
~
рubНс Cirr.::le (.) {
publjc Circle (strlng паше): b ase (nюне) I I
II Тепер. Circle ;ЦОmkeН "ПОRИКaIJ1Ь". qJt о~оCSра5~IJ1Ь сеея..
pllblic oVerride 'vpid Draw ,(}
J
CODsole. Wт. iteLlne ("О'тобраЖ~е ()~Р;y':!!iliРСТИ {О )" I pet~a!r!e);
-
238 Часть 11. Язык программировани~ С#
ECT~ два варианта решения э-той nробле--МЬL Можно ПРОСТQ изменить :версию
Dra w () Р(.lДwгелН. используя ключевое CJ]OJilO оуе r r 1 de. При та:ком подходе тип
Tr,ree'DCi:rcle :может расш.ир:И"ть возможност.и поведедJ1Я родителя т3к; .как тре
Руется.
Nщ.rернативой. может быть ИQПDЛЬЗО'ЩЦiие юrюче.вого слова fiew (с членом
Draw () типа Tb.ree-DСirсlе). Э7'О · а:вноеУК~ЭaI-IJ-Jе того. 'N'O ре;uиаацияпроиэвсщна
го типа должна. cнpъmaтъ neрсnю РОДИтemt (это MO~ 1;IОJ-щдобwtьсн тшда. когда
по.лученные извне программы .NE'Г не. соrnасую:гся с пр.ограммами. уже имеЮIЦИ
мuтя У вас).
}
r
240 Часть 11. Язык программирования С#
11 Мanag8r - это
Employee.
Еmр1о уее mо опUпi t: = new Manager ("MoonUni t Zappa",
2 , 20000, "1 01-11 -1321", 1);
/1 P'l'SalesPerson - это Sa.lesPerson.
SalesPerson jill = new PTSalesPerson("Ji11",
834, 1 00000 , "111-1 2 -111 9 ", 90);
1
- - - - - - -----------------
j I CQXptuцeнue 1II!t'ашо••
TheMachine. FirеТhisРеrЕЮП (mcюпUг.:i:t); // "mo01JUnj,.t." - Э~О !щрlоуе~.
TheMael1il'l.e. Fi reThiBPerS,O!1 (.j il1) ; 1/ "jill" - э~о Sal8sPerson.
в дальнейшем програММ1-IЫЙ код йсполъзует :в ПРОИЗВОДНом '1'ИUе неявное npe-
образовшmе и:а базового дласса (Employee). Но что дела'lЪ. если вы хотите уволить
служащего по имени Frапk Zappa (информация а котором Б настоroций момент
хранится в ССМЛltе System.Object общего ВЩJ;в,)? ЕсJШ передать объект f.rank н:е
ПосредствейНQ в TheMachine.FireThis'Person 1:) так, как ПОка3аН/) :ЮiЖe:
/1 Manaqer - 9'1'0 оЬj·ебt, во. ..
оЬ] ect fXiiJ,nk = new MaDager ( .. FriiШk Z:appa" ,
:3 , 40 О О О, '1 111- 11-1111 ". 5);
Распознавание типов
Статический метод TheMachine.FireThisPerson () строился так, чтобы он мог
принимать любой тип, nроизводный от Employee, но возникает один вопрос: как
метод Иузнает", накой именно производный ТИП передается методу. Кроме того,
если постynивший параметр имеет тип Employee, то как получить доступ к специ
фическим членам типов SalesPerson и Manager?
Язык С# обеспечивает три способа определения того, что ссъuша базового клас
са действительно указывает на производный тип: явное приведение типа (рассмо
тренное ВЪlШе) , ключевое слово is и ключевое слово аз. Ключевое слово is воз
врашает логическое значение, указывающее на совместимость ссьшRИ базового
класса с ДЩtНым проиэводным типом. Рассмотрим следующий обновленный метод
E'ireThisPerson().
public class TheMachine
(
public static void FireThisPerson(Emplayee е)
(
if(. is SalesPerson)
{
Сопsоlе.WritеLiпе("Имя уволенного продавца: (О)",
e.GetFullName()};
Console. Wri teLine (" {О) оформил (а) {1) операций ... ",
e.GetFullName(}, ((SalesPerson}e) .NumbSa1es);
if (е i.s Мanager)
{
Console. WriteLine ("Имя уволенного клерка: {О}",
e.GetFu11Name()) ;
Сопsоlе.WritеLiпе("{О) имел (а) (1) опцион(ов) ... ",
e.GetFu11Name(), ((Manager)e) .NumbOpts};
'rf13B8 4. Язык С# 2,0 ~ объектнь-ьриенти,роваflный ПОДХОД 243
эдесыo:[loевоеe CJШ1Щ i$ ИОПО:Т,fьауется ДJIЯ. ТОГ!'), чтобы ДИНaмwJе~щr Qцр~деди'Гь
Тип работшща. Чтобы ПQлrцrть ДОСl1'д к свойствам NvmbSale,5 ИЩI NШfiЬОрts, ВЫ
ДОJDIЩЫ :ИIrПОЛЫЮВ~ТЬ ЦВl.iОе приведени~ типiJв. Альтернативой 1III:Оrnо бы быть ие с
ПOJlызовщще КJIЮЧСЩJГО ,слова ~S для получения СChLJIJ:rИ на произвqдный тип (если
ТИПЫ НРИЭТQМ ОЮЩ(уТСSl н~с;овмеСтимыми:, ccьtJ1Кa пол:учит значение шй :Ц.
SaleBPersO[1 р = :е ае Salesf!e,rs'onj
i f (р ! = r.-1.111)
С::олsоlе.Wrlt'еL.inе ("'Число продаж: {О')" I р.'NШllb5аlеs);
Замечание. ИЗ ~лавЫ 7 вы узнаете, ЧТО такой же nOДXOJJ,. (ЯЗI-IРе nриведен~е ТИt101iI, is 11 as) может
иtmользрватьсяпр'и получении интерфейсных осылок из реШJl.1ЗУЮЩero типа,
П'арциanьные типы С#
в С# 2005 вводится новый модификатор типа р а, r t..iq: l, который UQЗВОЩIет
опреде.лятq С#-тип в. несЮ).iIЬЮ!И{ файлах ".CS-. Предыдущие .6ерсии нзыка С# Tpt:-
f)овали, чтобы весь програММJ{ЫЙ RСЩ определения типа содержалс.f.l в пределах
I'ЩНОro фa:йJJа '" .СВ. С учетом того, что сlt-класс ПJЮИ3ВОДСТЩ~ШiОТО УРо:ВЫН может
содержать с@тни строн npoгpaммв:OTOROдa. соответствуцнций фaiЩ мощет OK~aТb
ел достаточно объеl'V1НЫМ.
В таких слyqаях было бы хорошо иметь возможность разде.тщть реализацию
типа на неCRОЛ;ЫЮ файлQ:В, чтобы отделить nРQГРаммиы:й код. I{Отt}рЫЙ в некото
ром смысле более важен, от других элементов. Например, Pl'СПОl;rh3J'Я для КJIacca
М~ДИфИRа11@Р part ia 1, можно поместить все открытые ч;пеквr в файл с именем
МуТуре_ РиЫ i с . cs, а приватнъrе IIOЛЯ дан:ных и В0домш"ателъные функции - в
файл NyTy:pe_ Pr±vate. СЭ.
244 Часть 11. Язык программирования С#
// МyClasB_public.cs
паmеэрасе PartialTypes
{
public partial class MyClass
{
/ / KOHCТPYJCTOPW·
public MyClass() { }
/ / OTxpwтыe чnеИil.
public void MemberA ()
public void MemberB()
// МYClasB_Private.cs
паmеэрасе PartialTypes
{
public partial class MyClass
(
/ / ПРИ8аТИilе поп. даниwx.
private string someStringData;
/ / ПРИ8а'1'Иilе 8СПОllоrа'1'e.n:ъИilе чnеИil.
public static void SomeStaticHelper() ( )
Это, в частности. упростит задачу изучения открытого интерфейса ТИIlа для но
вых членов команды разработчиков. Вместо изучения единого (и большого) файла
С# с целью поиска соответствующих членов, разработчики получают возможность
рассмотреть только открытые члены Конечно, после компиляции этих файлов с
помощью с s с • е хе в результате все равно получается единый унифицированный
тип (рис. 4.14).
!'IANIFEST
• P.г~.lТyptl.
"'.
J!; • Por~ypos.PrDpertles
Зilмечакие, После рассмотрения Windows F1;Irms ~I дSp .NEТ вЫ поймете. что в Visual Si(JdiO 2ЬО5
ключевое слово part l1З 1 используется дня раэделен\oiЯ' t1РОГРЭММl;Iоtо кода, reHep~1pyeMoro
инструментами разрaБQтки. У1СПОflЬ$УЯ этот ПОДХОД. вь! можете сосредО'F0"1ИТЬ'СЯ на ПОlillже
пqДJфДl1ЩИХ решений и не азботитьсяоб aвтIЭМaтwtески генерируемом I1рограмМ!1О>М кеде,
Документирование ИСХОДНОГО
кода в С#с помощью XML
в завершеFЩЕ: этой rnaвы мы pactZМlYI1:!i'Th.I специфичесr<ие для С# лексемы коммен
тариев. которые DОРОЖДают ДШ<уМентaциro цpoгprow.mOTo Iюда на базе XМL. Если ВЫ
ШYfeете опыт i'Iроrpамми.р<>вания :наязы:ке .Java, то, с'корее всето •. зЫаете об ут:илите
lav'advc_ Используя javadoc, МЩЮIO ЦР~ElраТ'Н'IЪ l'юхо.цн..ь:Ш IЮД Java в соответству
ющее HTML-npеДСТ81Щe,I-щ:е~ 'Модель ДIiJI~~нтировалия, при:вятая в С# , Оказывается
немного :щIОЙ в том отнощении. что ЦРl'щес;<:; лреобрааования ROмментарШ'в в XМL JШ
Дf.reтCH LЩООТQЙ IЮМJllИЯТОра .(upи ис;пользoвaюrn ОПЦlilИ Idщ::), а не ОСобой утилигы.
Но поq~ для ДОliументировадия опредr.лений типов используется XМL. а не
НТМL? J)щ:внщr ЦJЭИЧИН;;L в том, ЧТО XМLобеспечивает Ьчеm. IПИJIORие ВОЗМОЖНQ
ста, Пое1tоль;Io/ XМL отд~JШ!n, определение данных от I1р.еД(:1'эвления 'ЭТИХ .данных.
к JI~жащем;у в ()СШJВf: XМL-KOДY можно применитъ любое XNIL"преобразование. по
з.вЬлпющее О;fОбразить документацию лротра:Мм:но:го HQДa :в одном из множества
дwтупных форматов [МSDN, НТМL и т.д.).
При документировании С#-ТИIIОВ в формате XМL пёрвой задачей ЛВll.Яflтс,я БЫ
БОРОДIШI'О из двух в3 риawrов нотации; 'l"pо:И:ной косой черты [1/ /) или прИ3нaRa
:комментария, который начинается КDМбинзцией косоЙ черты и двух звездочен
(/**). а закавчиваетсн- кo:мfjиняцией авсадоЧ1Ш и .коСОЙ черты ('" 1), В nOJ1.E .до:к;у
ментирующето комментария МDЖно исшiЛъ:юватъ любые XМL-элементы. включая
элементы рекомеццуе:мor{l набора. OIIИсанны:е 11 табл. 4.1.
Таблица 4.1. Элементы XML, pe'IGOMeH)J;YSMbte ДМ1 ИСПО11ЬЭQваНИf1 в комментариях
к программНому коду
ХМL-элемент
ОписаНltе
докvментации
11/ <summa.ry>
1/1 Этот ХОНСТРУХ'1'ор позвоnя:ет установить наличие JШха.
/ 1/ </SШlll1l.8ry>
/ I I <param name="hasSunroof"> </param>
public Car(bool hasSunroof)
{
this.hasSunroof = hasSunroof;
1// <sшnmary>
1// Этот метод позвоnя:ет отхрыть :nюx.
11/ </summary>
III <param name=" s tate"> </param>
public void OpenSunroof(bool state)
(
if(state == true && hasSunroof == true)
Console.WriteLine("OTKpblBaeM люt<:!");
else
Console. Wri teLine ("Извините, у вас нет люка.") ;
/ / I <SUПlll\a.ry>
/ I / Точха входа пркnо_ения:.
11/ <1 sшnmary>
static void Main(string[] args)
(
Сат с =new Car (true) ;
c.OpenSunroof(true);
csc /doc:XmlCarDoc.xml * . CS
Гnава 4. Язы.: с# 2.0 и ебьектнр.ориеН-ТИjiJованн""И ПОДХОД 247
в Vjsual Studio 2005 можi-i.о уУ<а3аТЪ имя файла с .xmr.-до~нта:циеЙ, исполь
зуя вкладку Build оКйа свойСтв (рис. 4.15) .
r'~- J ~~'rд~~~О])-'--':i
1~ ,--~~----~-
Pl8tt..m:~~м[A>wСМ . i~;----1 :
.::'==:::=== ~
~ ВЦId 0фIt ~~ -. . ~--"':-_',~"':-==-~_ ,____~ '0 ~o-.- 0- . ~ .'
I
L::, •.. ~ -",<,- . " : ;';" _. С .~. _. _ _
CМM80J1
Onисаtlме
формати:ровat4ИЯ
Резюме
Если вы изучаете .NEТ, имея опыт работы с любым другим объектно-ориентиро
ванным языком программи:рования, то материал зтой главы обеспечит сравнение
возможностей используемого вами языка с возможностями языка С#. При отсут
ствии такого опыта многие представленные в этой главе понятия могут казаться
непривычными. Но это не страшно, поскольку по мере освоения оставшегося ма
териала книги вы будете иметь возможность закрепить представленные здесь по
нятия.
ГЛАВА 5
цикл существования
объектов
В цред:ыдущей главе мpr потратили достато'ПlО много :времеlШ на 1'0, чтобы на
Y'QIJ'ься ~троить ПОЛЬ30ВатедЬСRие типы масса в С#'. в ЭТОН 'Гл.аве мы выяс
НИМ. как среда CLR ynРIШЛЯ~ уже раамешенныIlm объектами с поМощью процеt.са,
:ноторIЩf назr:цвается !'-бор~ой ЩJсорц- Лрограммистам, исrюЛЪ8УЮЩИМ C4l. tUJ при
ХОДИТСЯ удаЩI1;Ь объ~К'гы из цqмЯТИ "вручвую" (напомним. что в С# вообще нет
КЛючевого слова delete). Об'Ь~'Тbl .NEТ JЩэмещаются в области naмяти. RQТОРая
Н'Ззыва~С_8 .!Jn;pавl1яелwй дuндмuческой памятью. где 31'1'/ об'ЬеJtТы ~ не-который
подходr.пцИЙ момент будУТ автоматически yниqтожены сборщиком мусора.
б
publlc Car П {)
publi·c C<1ir (S't r irJg пате т int. speed)
1
petName = пате;
---
250 Часть 11. Язык nрограммирования С#
currSp = speed;
class Program
(
static void Main(string[] аrgэ)
{
1/ Создае~ся новwй объехт Car в дииаиичесхой памяти.
11 ВОЗJlращается сClol.JПltа на этот об ..ехт (1 refToМyC:ar' ) .
Сат refToMyCar = new Car ("Zippy", 50);
1/ операциJl С#, обозначаеман точкой (.), ИСПOJlЬзуе~СJl
/1 со с:cw.nочноЙ переиениой .ц.пJl BIoV!IOBa членов этого об-.екта.
Console.WriteLine(refToMyCar.ToString());
Console.ReadLine();
Динамическая память
Стек
l refToMyCar I
~ Са,!"
Обратите Вl'IЮ<laJnJ~ :на то, что ссылка на объект (myCa:r;) бьта co~дaнa иепо
среДcnJещIO в методе ,MakeACar () и ~e Uередавалась за пределы области видимо·
сти onределнющеrозту ссъи:ш:у объекта (НИ в виде :возврanфeмоrо значения. ни в
виде дараметров ref/out). Поэтому ЦQ~e завершения рабt>'i'Ы вызванного метоца
ecыnкa myC';:I r СТЩЮВИ1'C,fl недоетутюЙ;. ]ij соответствующий оБЪtlli'Т Сат окззыIа·.
ется КЩtдuдamом для УДa!Ifе;щщ в ~MYC()P~. Однако следует l1OJlИ:М:a:JQ, что БЫ не мо
ще:rе rарантжровать H~eA.!Jeнвoe удалmmе эт.о);'о. объек:га :из памяти сразу же По
Эа!Верщении работы MqxeACar ( j. в этот момент можноrарантИрОвать тольКО то.
что цря следующе~ сбор~е ~copa в оБщemlыRвой среде ВblПoЛНення (CLR) объект
myCiJ.r можe-r быть~ез оцасенцй уничтожен.
Вы. несомненно, обнаружи.те, что прuграммировмше 111 окружении. обеспечи
вающ~м автоматичес~о сборку ыусцра. значительно упрощает задачу разработ~
кв ЦJЩлошеню1. Про:rра:м:м:иеты, иcr:roлъзyющие С++. знают о том. что. ес.ilИ в С++
заб~ ~РyчIryЮ удали1~Ь размеIЦеН1-ше Б ДИRaМИЧесной памяти объекты, может
ПРОlJ30Й"'PI' "уте<ща ГЩмнти , На еамом деле ЛИlrnи;!(au;ШI утечек паМяти sшл:яется
П
Замеч-анме.. Если вы ИМ99те опыт рil~р~ботки пррграмм G ИСlТOJJьэaвatJиеN СОМ, то знайте, что
объекты' .NEТ Не Н(),[1ДЕ!РЖИI!_3ЮТ С'ЮТ'lик ef.!YTpel-lfl\llХ СОЬ/J1ЩС, ,t)ОЭТОМУ vrчrввляемые объекТЪ/ не
предлаГf}Юl' тзкие M~TOды. как Аф;iRеf () и Releas€ ( ) .
Динамическая память
s ta tic vo i d Ma in( ) 1 cl I С2 1 1
!
Ca r c l = new Car () ; t ) t
Указатель
Ca r с2 = new Ca r () ;
} на следующий объект
На рис. 5.3 представлен возможный объеI<тный граф для только что описанного
сценария (цаправленные стрелки. связывающие объекты в таком rрафе, можно за
менить словами ~зависит от" или "требует". - например. "Е зависит от G и косвен
но от В", 1\ не зависит ни от чего" и т.д.).
Динамическая память
t
Указатель на следующий объект
Рис. 5.3. Объектные графы строятся д1lя выявления объектов, достижимых из корней приложения
Динамическая память
А Iв I D I Е IG I
t
Указатель на следующий объект
Замечание. Строго говоря, сборщик мусора использует два разных фрагмента динамической па
мяти, один из которых предназначен специально д1lя хранения очень больших объектов. К этой
динамической памяти при сборке мусора система обращается реже, поскольку при размеще
нии больших объектов возможные потери производительности выше . Тем не менее, вполне до
пустимо считать "управляемую динамическую память" единым регионом в памяти.
Глава 5. ЦИКЛ GущеСJSDваНl<tя объектов 255
Генерации объектов
Когда среда CLR uытзетея. найти недоступные объекты. зт(') не здачит, что будет
рассмотрев буJo\:.В.CЩЬНО"RВЖДblЙ объem:. размещеННЪ!Й в управляемой Д1Щамич:е~кой
пампти. ОчевИДШ~', "Что это требовало бы слишком МIIоrо Вpt:мени. особен;но в ре
aJlЬЩill{ (т,е. БолыIх)) ПР:m:JОЖe.E:i:ИЯX.
ЧТОQЬ\ ОПТИМJр:ировать процесс, 1СЗЖ'ДЫЙ объeкr в динзмичес:rщй ПЗМЯn'l цриnи·
еы:вается опреДf.nеннОЙ "генерации". Идея ДОQ1'аточно ПРОС1:а,: чем ДО.IIbШе объект
существует' в ДW':Iамичёсжш IIaМЯТИ, тем более веРОЛТ}JО ТО, что вн дол:щен там '))
оставаться. Н<;lDfJИМер. объект. реализующий М.аiл (), будет находиться в ца.мяти
до тех пор, ПOlса протра.мма не аакоWnnся.. С другой стороны. оБЪeRТЫ. ~OTopыe
HeдmJHO размещены в динамической памЯТИ, ::вероятнее Bcero. станут вскоре недо
СТИЖИМЫJ14И (н<шример, объекты. созданные в рамках об:na.с'ЦI ВИДИМОj::ТИ ~eтoдa).
При этих предполож~IШlX ШюfщЫЙ обгьент в дm'tами'iеской пам~ можно oтнec~
R oд.нa~ из ['Л(Щ},ЮЩИХ RaТeroрий.
• Генерация 1, Объекты, IOOТ0рые ~:а~режилиW gднy сборку мусора (т.е. были обо
значены Д:n~ испощ.ЗDВания в процессе сборКИ мусора. :но:не бъt.ли УДЩiе:ны
по той цричине. ~O в ДИНaм}f"lеско:И. пам.вт.iI оказалось достаточно Mef.-ra).
• П?иеРUЦWl. 2. Объекты. "пережцвпm.е" нес:щ)лыш сборак мусора.
... rенepвцtlя:О
Ес.1JИ ,все объецтh.l ~Hep~ О уже рассмотрены. но памяти :все равно еще Не
ДОСТаТочно, то рассматррщается "достижимоcrь~ объею.'ов teнерадJШ 1и DЫПOЛНJ'.l
е1'ся еборRЭ! мусора среди ~ТИХ Ьбъeкrnв . "ны1ивпllIе" объекты rtmерации 1 "ПePeXD-
1
r
256 Часть 11 . Язык программирования С#
дЯТ I~ генерации 2. Если сборщик мусора все еще требует дополнительной памяти,
тогда оцениваются объекты генерации 2. Здесь. если объект генерации 2 "выжива
ет" в проце ссе сборки мусора, то такой объент сохраняет ПРШiадлежность к гене
рации 2. поскольку это предел для генераций объектов .
Итан. с помощью назначения признака генерации объекта м в динамической
памяти более новые объекты (например. локальные переменные) будут удаляться
быстрее. тогда как старые объекты (такие как. например. объект приложения про
граммы) будут "беспокоиться" значительно реже.
Тип System.GC
Библиотеки базовых классов предлагают тип класса Sys t e m. GC. который позво
ляет программно взаимодействовать со сборщиком мусора. используя множество
статических членов указанного класса. Следует заметить. что непосредственно ис
ПQльзовать этот тип в программном коде приходится очень редко (если приходится
вообще). Чаще всего члены типа Sy ste m.GC используется тогда, когда создаются
типы. использующие неуnравляемые ресурсы. В табл. 5. 1 предлагаются описания
некоторых членов этого масса (подробности можно найти в доиументации .NET
Framework 2 .0 SDK).
Еслд вы сочтете, ЧТО будет ВЫТОДНО выпоJU.IИть сборку мусора:, вы можете явно
'Начать процесс сборни муоора. так, Kfili и(щазано шtЖe.
е 1 ;,.~
Cort s ole. Wr.i teL iТl'e ("Щ;ъекта tonьOfObjects [9(00) уЖе нет.") ;
// System.Object
public class Object
(
1/ OIaиClJl/8 :кОКПИJUЩИИ!
pxotec:t'ed. overri!de v oi d Finalize (] { }
}
(TOJIЪJl:O ДnRпринера.!)
1
262 Чаоть 11. Язык программирования С#
RогЩl с точки зрения сборщина ~c.Dp-a прИХодИт время удалить объект из па
мяти, проверJtЮТся ~демепты о<шред:и фпнал:изaцш.i, и соответсТItУЮlЦйЙ объект
I(ОПИРуетС'н из ДИW1Мичещюj) памнтй в дiJугую ynpавлнемую структуру. которую
.Называю-r Т'абдицей эяе.мeнmaв, OOemУПНЫх д,'IЯ фWtй:л.uза'Цi!tt. В Зт!J'r Мt'Iм.eHT CQS-
дает.ся отде;rtьный поток. з~д.аче;й которого я:вл.нется вызов метода Firialize () при
следуlOщей сборке .мусореl для каждр.го объекта из таблицы элементов. дoeтyuнъц
ДIIЯ фИЕ!али.зации.. С учетом ЭТОГО ста:новится..асно, что ДJlЯ ОRончатеДЫfQГО уни
чтоmeния объекта ПО'1'ре6уетс.я Щl}I'. минимум две ЫJЮцедуры сбор~-и мусора.
ТакиМ образом. )}:OTj'f финали~ объек;та и гаравтирует. ЧТо. оБЖ1>Т сможет
освоБЩ:цлъ неуправляемые ресурсы, паевом природе .а.та працедура оК::t.3QIВается
ведетермиючщванной Н, :1\ С,вязи С nроис.ходтцими ·за 1:\Улисами" ДОПQЛlштеЛЬНЫ
ми I1pоцессами, доcrа:п,}чна меДJJеннОЙ.
,
1
.....
ЭТот при:мер з~таВ.jIЯет ВI[''nGМНИTh еще ОДНО 11рaDИЛ:О раб.оты с типами, предпо
лагаюЩИМи сборку мусора.
Если с помощью ildasm.exe взглянуть на СIL- код метода Main (). то вы обнару
жите. что синтаксис using на самом деле разворачивается в логику try/finally
с ожидаемым вызовом Dispose () .
. tcy
{
/ / end . try
finally
{
11 Запрет финa.JtиЗации.
GC.SuppressFinalize(this);
disposed = true;
-МуRеsоurсеWrарреr()
{
11 Вызов нашего вспомоrа'l'8ЛЬноrо метода.
11 Значение "false" уJCазывает на 'Ро, Ч'l'о
11 ОЧИС'1'ху инициировa.Jt СбоpщиJC мусора.
ОеапОр (false) ;
ГЛЩlЭ 5. Ц~fК.110уществования объектов 269
Обратите ВFIИNaRие на ТО, 'ЧТО T~.цepь МуRеi.IO:ю' се'iJrарреr сщредt'ЛЯет n:pиваТ
!wйвcIJомогателыfblйм.етод с имен~мСlеаnUр () .. Если для ето ар1"JМfШ1'D. указано
t:cue (ИСТ:иFrn), ЭТО3Iiа'Щ;т, 'ЧТО' сборку му.сора ини .циировал пОJtЪэователъ объе~та.
и тогда ~l ДОЛЖНЫ ОСВОБОДИТЬ и управляемые. :и нeynра.вляе:мы..е pe<;ypcbI. Но ' если
·уборка" ищщииро-вана сВорIЦИ1tOМ мусора" ТО' при вызове eleanUp () следует}'l<a·
эать fa 15 э (лщпъ). чтобы внутре,нн.ме объекты не :ОСБобождалисъ (trос}tО'ЛЪRy мы не
можем rараитироваТJ;>. ~TO QНИ нее еще НaxQДЯТСЯ в памяти). Наконец. пgред вы
ходом из Сlеi'),Л'LТj:.() 'Ч,IJ,е~-lJере,j'dеннан di s posed Jlогнческого типа устанавливается
равной t'X'U'e, чтобы Dispo5e () МОЖНО было вызывать МНОГОRратяо без ПОЯDЛеНИII
сообщений об OIIJ:Ц6~_
На, этом RЗ.IПе обсуЖдение того. "ав среда CLR управляет объектами с помощью
сБОРIm мусора. завершаетсв. ОСТaJIИСЬ нерассмотре1-IНЫМИ еще ряд, вопр.оеОJi. свя-
3~ с ;ПРОЦ~ССОМ сбор:iШ. мусора (это. 1ШIфимер. сл.абые ссылки и восстановле~
н:ие объектов,), :Но вы теперь име;:етедостаточно ЗНaJ-ШЙ Д.l.Lff т@го. чтобъr продолжить
и<.:1'.ледовmtиё ,Дa:m'I'ОЙ темы ,самостоятельна в удобное для вас врем>!!.
Резюме
Целью этой главы было обсуЖдение лроцеСQ3 (:QQPIW мусора. Бы мргди убед:~I'1'I:o
СВ. что сБОРЩПН м.,vсора наЧИnает раБOJy TO)~O ТОI1Щ., JtQгда c-rаноm,IТC.fI :невоамО'ж
НЬ1М выделить Clеобходимый рбрем уцрам.яемоЙ ДЩ'Ш_l'dИЧе"скоj{ ТJ.a.МЯТИ' (ПЛИ ROrдa
из памяти выrp.ужаеТС8 ЦOM~ дадного ир.илож.ещия). Eы Mo~eT~ бытъ уверены в
том, что сбоРJta мусора будет въщолнена в оптимальном pCi{ЦiМe с помощью соОт
ветствующего алгоритма М1crosoft. использующето генерации о'БЪf\КТОВ, вторПЧ8:Ы€
uотоь."И для фюtализаЦJ{R 05ъе1\ТОВИ области уцравллеМQЙ ДИН<ЦilliчеСRОЙ naм:Rти l
предна.з.начtНliые длл pa.-змещенЩ! болъших об'!,t1R1'0В .
В этоi1 же Гдаве объя:Сlщется. Юlli С домощъю типа' класса $yst~m. GC в.ааи:мо
.n:еЙствО'ватъ со ~БОРЩИ1{()"1\iI мусО'ра. Это требуется ПРPl С'О3ДЩiИИ ТИПОВ. ПРе>цусма
-тривающих ф:анэлизацшо :nm;I О'СJЮБОЖJIeRJiе peeyp~O'~. 'JI.щы" Пj?еАУС'матриваю:щие
фt>шализвцюо. upедt:.'Т/ц!л1UO'Г сО'бой ющс,сш с п~реоцределенн;ым виртуалъным ме
'ТОДОМ S у stещ .'Qbj ect, Fi !).a 1 iz:e .( }, RОJ'ОрЫЙ' (В 6)ЦIJrщемJ дО'лжен , обесIIeЧИ'I'Ь осво
БОЖДt$:ие н<=ynравля:е.мых. ресурсов. Объекты, пред,усм~тривающие освобождение
ресурсов. п:влmoтся RП,аесами {ИЛИ СТРУR'ryрами;). 13 .котО'рьц реалиауетс,я интер
фейс lDisposa.ble. В рa:мJЩК этого подхода ЦОJIbЗQl3а')'еJ:IЮ объекта l1редnзгается
открытый мехОД. 1w"I'ор.ы.й долщен быть ВЫЗВaF,I пщц,зоват~лем ДЛЯ ВЫПОJUirени.н
lЖ)"Треннffii "'уборки сразу же. 1ЩК только это пО'требу~я. НакОfJёц, ВЫ уЗ'li:.!'lJШ об
Ц
Замечание. Чтобы сделать при меры программнога кода, используемые в данной книге, как мож
но более конкретными, в них обрабатываются не все возможные исключения, генерируемые
соответствующими методами из библиотек базовых классов. Приемы, представленные в этой
главе, вы можете исполЬзовать в своих реальных проектах по своему усмотрению.
ТaJ~ОЙ подход следует tIpизнать Дa.JreНИМ от идеа.цьНОГQ, ес.ци учеетъ ТОТ факJ.:, ЧТО
}(oнcтa:rera Е F1LENOTFOUND является mnnЬ1ЩСлОВЪ!М знач.еЫJ1~l, а не lmформаци'.
оIo-Iым агентом. предлалuощим решenие ВО3I-щщпей проблемы. В ИДt:~е хотелось
бы ПОJJY1lатъ название оши.бки, сообщение о ней и дрyryю полезную информaцmo
в ОЦНОМ псщете вполне опреде-.ленноrо вида (и имещш это предда,та;етса в рамках
СТРУН'IYPированного подхода 1\ обрабQТЕе псюцоч.еНИЙ).
В дополнение I{ приемам самого разраБОТЧИRa. Windows; АР! предлагает с~тнй
КОДО'В ощиБОI\. }toTopble поста.влщохс·я в виде 11- de f i па. HRiESQbl\ s, ТaRже в ВИД@
многочисленных вариаций булев.ых знач.ениЙ (bool. Э О'Qi, . VARIANT_B001 и -r:.д.) .
.многие разработЧJiЮi программ на язьше C+~ (а TaJVIre VВб) в ра:мках модеJШ СОМ
1IВHO ИJ.Uf ненвно npименнют оrpа:аиченыый набор стандарт.иых СОМ-интерфейt::о~
(например. ISupportErrotrJnfQ. IЕrrоrlлfо. IСrеаt6Ецor Infо ). чтобы предоста
вить СОМ-клиеmy ~формацпI(> об ащибках.
Очевццной проб:лемой этОй уже устаревшей схемы .лВ:IIЯ.еТ(:jJ отсутствие ~им
метрии. каждый из rroдхддов более или менее уклaдъmаеТСJ:l в р~и СВОеЙ &01-1-
жретной ТexElологии.. RоЮtР!':Тl{оrо лзыка И, В03можне. даже в p<1М1ll1 коюсретноrо
проекта. Чтобы подожить конец н~уемцоll4Y буйетву разнообразия, IIJIзтформа
.NEТ предлагает СТiil.НДартную техцодarцю генерироваFJИ~ и выявления ОШИ~(J~
ср(дыI выполнения: стру:ктурирозадную оf5работЕ;' ИСКТIЮчений - ~ОИ (S1ruсtш'€d
~ception Handling - ЭЕН).
nре.имущества предлагаемой технолщ'ии закдючается в ТОМ. что теперь раз
работч.ики могут использовать в областц обрабопси ошиБОR унифици:ров~
nO,UQД, обдn1Й ДЛЯ все,х лзьщоs. обесцечиваюIЦЮt поддержку .NET Таким оБРС!:З(J~.
способ обработки ошибок в СИ 01taёiьшается С:J-штаксичесии аналогичным Т/щ()Ц' 00-
раБО1"lt€ и.вVВ . NEТ. и в С+" еynpaдlIяеJЩiIМИ расшдренитm. л.ри этом синт;шсис ,
ИGпom,аУ~МЫЙДЛ1J генерироеания и выявле.I-ШЯ ~СR.lJЮчеНИЙ между RОМnОНОВОЧ1Ц>I
м'» бл'ОЩL:МИ и грщmц~ <;истем . тоже <щззьmаетс,J:t один<щовым (.И это .!{ВЛл~ся
ДРnOЛЩiтедЬЮilМ преимущесnIOМ) .
Еще ОДНИМ npеимущесТВQМ обработ.tm ИОЮIЮчений в .NEТ ЩilJЩетГJl ТО , что l3М:e
сто передачи ПРОСТGГО ~защифрованного" ЧИСЛGвоrоздач~. иде.l:Ц~фИЦИРУIO'
щего проблещ . И'сЮ1Ючt:НИJII предСТаБJlffi9Т СQбой объеl\Т1!f;. содер:щащие Щ)fl:ЯТНО~
Че1[овеку описание ощиQни. а также цодробnyю"копию
U
содержимого стmщ ~ы
зовов В момент ВОЗн;иI(нове1ЦП.l. исцлючитеЛЬRОЙ ситуации. ~ тому ,не вы имеете
возможность npедоставить RОF,!еч;80:МУ пользователю ссьщку с !Щресом URL" по но
торой пощ>зователь можеr ПОлучдтЬ подробную л~формацию о соотвеТСТВy1Qщей
IIpоБJIеме.
j
274 Часть 11. Язык программирования С#
митипами.
Заме'f8t\Ие.8 ,NEТ 2,0 Sys t,e,rn .Except iQn реализует интерфейс Exception, чтобы COOТBBf
стаУk:Jщие ФУНКЦИОН0:sJ.,ные вММОЖflОСТИ !liыди ДОСl)lflНЫ неУfФ8МЯемому программномУ коду,
СвоЙст.во
Data Добавnвно в .NE1 2д. ПреАЛзгеет КОл'l1еI<Ф1Ю пар Id1lочей J.I ЗI'Iг,'Iе~и.й (пред
стаеSIf:МНУЮ об'\:i6КТQМ , рёализующим IDlctiana!:y), которая обеспе.Ч1l1вает
ДОГJолнительную ПО{lьзоваТВЛbG~Ю информацию Ю' данном ИСlQ'(ючвни,И,
По УМОЛ'lаfl~НQ эта '(QЛi;1еlЩ~JI' ЯВЛl\ется nуотой
fleipLj tJ k Возвращае" I'!дpec U'RL файла спращ~и с ьписан.VJем ошибки вО воех подроб
н!>стЯl!:
InnerExcept iQI) ДОСТУПl'Ю толы(o д:11f1 4Тения. Может ИQf)QЛI:!ЗОВ~ПbQЯ ДЛЯ полуЧения инфор·
мации о r;rредыдуЩем ИСКЛЮчении 1111"1 ио~лючения)(, ставших причино.Й дан
Hpro иr;КЛlOчеIoiИЯ . Заnиоь предыдуЩих ~lCl<ЛlOчеflИЙ Qсуществляется путем
пер~д~чи .и~ КОНСТРУКТ0РУ саМОе(} последнего ИGКЛЮЧЕЖUlя
Messa1iJ'€> Доступно тqлько ДЛЯ LfТвния. В.оз. вращает Teti:cтoBoB описзнивдаl'fliОЙ ошиб
ки. Само сообщеltJllе об ·ощибке задается,. как пара:метр конструцора
1\/jrgetS,i le Доступно только дЛЯ 4ТЭНИЛ, Е30звращает rип М'еt h;о;dБаs е, nредлагаlOЩИЙ
самую разную' инФорМ<:lLtию о мето;ае, который генерирOEUlЛ ИСfWЮЧ6rние
.(То9t.гiпg () будет идеНТИфИЦLllравgrь им~ соответОТВУlQщего метода)
:J
276 Часть 11. Язык программирования С#
11 КОНС'1'рухторы.
public Сас () ()
public Car(string name. iпt c u rrSp)
{
currSpeed = currSp;
petName = пате;
currSpeed += delta;
if (currSpeed > maxSpeed)
(
Console.WriteLine("(O I п ерегрел ся!", petName);
currSpeed О ;
carIsDead = t ru e;
Гпавв' 6. Структурированна~ обработка искmочений 217
еlзе
ton s.ole,WriteLirJ~("=> GшrrSрееd = {[)}", ~UI.tSpeed);
МодUф~руем ЭТQТ мeтqд TaIt. чтобы 0}1 генерировал ИСЮnО9.ение при попыт
ке ИОЛ.ЬЗОВ~ПЩН увeJIИ.'ЧИ'lЪ CROpodn автОМООЮ1fl выше предусмотреННых ero соз
да,те:лем дределов. Для э'Юго' нужно создать й скоnфигурироватъ ЭIfЗe.мrmяр .к.ласса
System.E.xception. установив значение доступного TO:lIbl\O дЛЯ чт~ния свойс,тва
Mes,s,age: с помощью :КOНCTpyRТopa класса. Чтобы отправить СОQтветстщтющий
ошиб~е оБЪеН'J' вызывающей стороне. используйч:е .ключевое слово С# th.IOW. ВОТ
шm может вь;irmщеть соответСТВУЮЩall JI<10ДИфИJ{8ШШ ~eтoдa Accelerate ().
278 Часть 11. Язык программирования С#
currSpeed += delta,
if (currSpeed >= maxSpeed)
(
саrI sDead = true;
currSpeed = О;
else
Console.WriteLine("=> Cur rSpeed (О)", currSpeed);
Прежде чем выяснить, кю~ вызьшающая сторона должна обрабатывать это ис
ключение, отметим несколько интересных моментов. Во-первых, при генериро
вании исключения только от вас зависит, что следует считать исключительной
ситуацией и когда должно быть сгенерировано соответствующее исключение.
Здесь мы предполагаем, что при попытке в программе увеличить скорость ав
томобиля . который уже перестал функционировать, должен генерироваться тип
System.Exception, сообщающий, что метод Accelerate () не может продолжить
свою работу.
В качестве альтернативы можно реализовать такой метод Accelerate (), ко
торый автоматически выполнит восстановление без генерирования исключения .
Вообще ТОВОрН, исключения должны генерироваться только тогда, когда выявля
ются экстремальные ситуации (например, не найден необходимый файл, нет воз
можности соединиться с базой данных и т.п.). Решение о том, что именно должно
вызьшать появление исключений, должно приниматься разработчиком, и вы, Ka:I<
разработчик, должны всегда помнить об этом. для наших примеров мы предпола
гаем, что увеличение скорости нашего обреченного автомобиля выше допустимого
предела является вполне серьезной причиной для генерирования исключения.
Обработка исключений
Ввиду того. что теперь метод Accelerate () может генерировать исключение,
вызывающая сторона должна быть готова обработать такое исключение. При вы
зове метода, способного генерировать исключение, вы должны использовать блок
try/catch . Приняв исключение, вы можете вызвать члены типа System.Exception
и прочитать подробную информацию о проблеме. Что вы будете делать с получен-
Глаl1а 6. СТРУКтУРИРf)~анная обраОон.а исключе",ии 279
ННIМИЩ.ШНЫМИ, зависит. в оснощюм:. ОТ вас. Вы можете noмeСТИ'IЪ соответству
ющую ивформanию в файл отч!:та,эвnи~атъ ее в журнал рег.истраnии событи:й
Wmdo'ws. отправить ее по 'ЭЛfЖТРOIffiОЙ поч1,'~ aдми:ниt'трэ.торУ с:ш:темы иди пока-
3З.ТЬ сообщение с описщшем пробдемы конечному ПО.nьaoвaтeлIO. Здесь мы просто
вЫводим ннформациro в окно кщrСОJIИ.
catcn CE::XceptlCme)
{
Сс>л·sоlе .. WriЬеLitrе("\nН'I< ОШиt~)I<:а! .. ·"' * "1;
Co.neole. W.r:iteLiQe ("'Ме'Год: J О} ", е . Tar:getSite) ;
Соn.зо~е_ Wr·l.teLine С'1 с tюбщениеl ~ 01 п, e.l.'1es·sage) I
С;@пsаlе.WritеLinе( "исq.ОЧНИУ.; (О)" ., e.,80urce);
точником данных).
-
280 Часть 11, Язык программирования С#
Свойство TargetSite
Свойство System.Exception.TargetSite позволяет выяснить дополнительную
информацию о методе. генерирующем данное ИСIщючение. Кан поназано в пред·
ыдущем варианте метода Main (). при выводе значения TargetSet демонстриру
ется возвращаемое значение . цмя и параметры метода. генерирующего данное ис
Con·s·ole. WritE"Lln e ('' '\0' ~ * Е\ЫХО Ц .из 'сюраеЮТЧИI<:а исключении **~ ") ;
тусаж: . Accelerate (10) ; 11 ~O ие УС:kОРИ'1' авmоиоlSюП.,
Con sole . R,e.a:ctL i ne () ;
На этот раз .вы исполЫ\vете свойство N·eth;oдВа Ё; е . Dec larlngTypE:. Ч'Iобы опре
делить afiсоillЮ1'Ное Й::МЯ lШасса. (;генерировавmего оmиБRY (В дmшом случае &1'0
м'аса Зiшр1еЕхсерt ion .Ca I ). и СВЬЙС"I'J30 МеrпЬ€- rТуре об1.>еК1'8' Me -r:hо-dВа:sе.. чrобы
Щ{тп~[РОБать тип ПОРОДJ'IВшеr'о исключение члена (й том смысле, своиство
ЭТО или метод). На рис. 6.3 ПОRазан обновлен:ньrilвывод.
сво.йство StackTrace
CвoikTBO SУ8 tе~I,-. Е х с ер t i.оп . 31:.ack Tr,.'ice llО:з.воля-ет И,JIевтифицироватъ серию
вызовов. которые привели R Т!IскmDчитеJIЬНОЙ СИl'уanии. Вы не ДОЛЖНЫ уетанав '
лива'l'Ь значение SE:ac kTr a c e. ПФt:RОJ1ЬПУ это Д'елас-тсл автоматически в· момент соз
дания исключения, Для ИJ1ЛЮстраЦЮI uр€дt!олоЖИМ. что мы снова об~ОВИД1И лро
граммный ~OД cat.ch .
С'дt .:.'h (E;xcept:Ume)
j
Свойство HelpLink
Свойства TargetSite и StackTrace ПОЗволяют получить информацию о данном
исключении программисту. но конечному пользователю зта информация мало что
дает. Бы уже видели, что для получения :информации, понятной обычному польэо
вателю, можно использовать свойство System. Exception .Message. Б дополнение к
этому свойство HelpLink может указать адрес URLили стандартный файл справки
Windows, содержащий более подробную информацию.
По умолчанию значением свойства HelpLink является пустая строка. Чтобы
присвоить этому свойству некоторое значение. вы должны сделать это перед тем,
как будет сгенерирован ТИП System.Exception. Вот как можно соответствующим
образом изменить метод Car .Accelerate ().
public void Accelerate(int delta)
{
if (ca rIsDead)
Console.WriteLine{~{O) не работает ... ", petName);
else
currSpeed += delta;
if (currSpeed >= maxSpeed)
{
carIsDead = true;
currSpeed = О;
// Чтобы вызвать свойство HelpLink, перед оператором,
// генерир~ объект Exception, создается
/ / ЛОJC8JIЬная переиенная.
Exception ех =
new Exception (string.Format ("{О) перегрелся!", petName»);
ex.HelpLin.k = ''http://www.CarsRUs.com'';
throw ех;
else
Consol e .WriteL ine("=> CurrSpeed = {О}", curr.spe ed);
catch(Exception е)
{
Свойство Data
Сврйство D.st.a объex:rа &уstеш.Ехсерtiол является новым.в .NEТ 2.0 и Ш!JЗВО;rn
Ет Доб<щИТЬ D объект иcюnочеН$ Д;ОЦОJЩJiтельную информацию Д!IЯ ПОЛЬЗОЩ'lтеш,I
(шщример. штамп време}iИ иди ЧТQ-1'О цPYГOt;). Свойcnо Data возвращает объшц.
реализующий интерфейс с цмецем П)iсtior,d.rу. опредедеН1:{ЩЙ.з ПРОСТРЩiств{'
имеЕ System.Col1ectibn, РОЛЬ nрограмм.ировamш интерфейсов. кat< ц ПРОС1"рa}j
стВО ИМеН System ,Соl1 ection. раесма:rрИЩU()ТСЯ :в следУЮщей главе. Сеiiчасже бу
дет ДОСJ:аточ:но заметить.. что Н:ОJИеRДИЦ сдовэрей ПО3БО.ЩПот создавать МПOOlЩства
Щlач:ений:, :возвращаеМJ>IX IЮ значению ключа. PaccmotpI-J'Ге. щщример. CJlедyIOIIJYЩ
мощrфИКfЩИlO Mt'ТO~ Car .Accelerate О,
}
else
СБJ1s.о1~. writеLiщо: (IТ=> Curr6peed = {О]", currSpeed);
3атем нужно обловить J;IpОf'Vc.LММ:НYЮ J,югииу cat.ch для проверки того. ЧТОElНЗ:<lе
ние, возвра1Цаемо.е свойством 'QаЦ'. не рi1шво щ;йl (анач~:ние лиll задается ПD умол
чанию) Посл{'Э'того:мы испольауе~ CBP~CTBa Ееу и \1@1пе тида Diс.ti,щ,аrуЕntrу.
чтобы вывести ПОЛЫlOвцтеЛЬСКIJе ДЩ-UIЫе щ:t 1СОI'JСОЛЬ,
284 Часть 11. Язык программирования С#
catch (Exception е)
p,u blic сыз з Аррl l С'а t i Cfл Е1 хсерt; Lоt; E 1oiC",,&, t i 0i'1
j
Подо,6но SysIem E x c-ерt i оп , 'l'Иll Аррl iСд,t-iоrйж серt i l~Tj не опр~де.'[Яе·г ника
ких цополнительных членов . :кроме набора ItIlliCTP)'It'YOpOB. С ТОЧJQJ зрения ф'УН;К~
ЦИОRaJll:;НОС-ТИ еД}ffiс-твенной цеm.ю Яу5t еm.Аррl :i с аt.iопЕ А с ~р ti,ОГl должна быть
IЩентифй:ка:ция nСIГоЧНИIW. (устрanим()й)оr:tIИБЮL При обрабОТИ::1;1 иск.щоче-ния, rro-
.л.учеmЮl·О ИЗ Syst-em. A-ррJ.iсаtiоnЕ хсе рtl.ол. ВhI можете nредпо.rrаг<!.тъ, что пр~ "
ЧИtiой m::щвлeJ{йл :исlVD0ч.ения БЫJI ,I1J'юграммный КОД ВblПол:внеиorо пр~ожеНДJl.
а lIе' бибщroтеки оа..з()вых классов .тт.
CarIsDeadEx c eption ех =
new CarIsDeadExcepti o n(string.Format("(Oj перегрелся!",
petName»);
ex.HelpLink = ''http://www.CarsRUs.cOJll'';
ех . Dаtа .Аdd("Дата и время",
striпg.Fо:rrnаt("Автомобиль сломалея {О}", DateTime.Now));
ех . Оа ta . Add ( "Причина", "У вас т яжелая нога. 11) ;
thriDw ех;
Пока что глубина ваших знаний .NET не позволяет вам понять роль атрибу
тов и сериализации объектов. но сейчас зто и не важно. Соответствующие во
просы будут рассмотрены позже. А в завершение обзора, посвященного вопросам
создания пользовательских исключеций, рассмотрите заключительный вариант
CarIsDeadException.
[Serializable]
public class CarIsDeadException : ApplicationException
{
public CarIsDeadException() { )
public CarIsDeadException(string message) base( message ) ( )
publi c CarIsDeadException(string message,
System.Exception inner) : Ьаэе( message, inner) ( )
protected CarIsDeadE.xception (
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Ser i alization.StreamingContext c ontext)
: Ьазе( info, context ) { }
~tI ==
='filriil• :~it==='-'------1
~ Itread>
!iilw I
JOolIf
~ inde'W 1
., ~.~
,c:at·ch (.Argumen,tO,utOfRangeEKception е)
\
1/ Обработха Argument()qtQfRa'ngeВ,xo~ption.•
Пр~ co~д~ множества РЛОRОВ patch следует учитывать ТО. чт.о сг.енер1'lр.о
ванное ИСWIЮЧ;е1-IИ~ буд~ об~бОТIi1Щ М ПеРВЫМ подходящим" блокам aatch. Чтобы
поин.rъ, ЧТG l'8Щ)е "пepв.ыij Падх9~" блок catch. добавьте в предыдущий фраг
ме;нт ПРОСР!!ММflОГО ICO,lG:t «,:ще Одщi блан 9ё;ttch. который будет обрабатывать все ис
КJ}J9чешц1' JJoqle СаrlsDеаdЕ,хсерti 9Л и АrgumепtОutOfRaл.g еЕхс,ер t.iоn, въiпОЛВЮI
ЩiXВCJ,Т S.y~teJtl.1i1xcept ipn общеro вида.• ка;к ПОКНЗaRО ниже..
290 Часть 11. Язык программирования С#
try
{
for(int i = О; i < 10; i++)
myCar.Acce1erate(10) ;
catch(Exception е)
{
/1 Обработх& всех ос~&nьиwx исхпючений?
catch(CarIsDeadException е)
l
11 Обработха CarIsDeadException.
catch(ArgumentOutOfRangeException е)
{
1/ Обрабо'J.'Х& ArgumentOutOfRangeException.
try
(
for(int i = О; i < 10; i++)
myCar.Acce1erate(10);
catch(CarIsDeadException е)
{
/1 Обработх& CarIsDeadException.
Глава 6', СТРУК'ТУРИРU&анная обрабОТК<I ИС.kЛЮ<lI:1НИЙ 291
cat.ch (АrgQlТlелt.оut,Оf,Rаfl9"еЕхсе,рtiО1! е)
f
/I О~ра,БОТkа ArgumentoutO:fRangeException.
саесь (Ехоерti,:ш е)
{
/J Здесь будУТ обраCSо'l'З.JW все ocwanl.!We ВОSИОII!2Щ8 ИC!CJШЧ8RИJJ r
1/ reиеIрируеlOofE! ottepaTOP~ _piUOC&Х ~.
}
иу
I
1'orlint i = ' О; i " 1О; i-t+)
myCar.Accelerate(10) i
caJ:,ch
., .
J
Очевидно. 'ЧТо Э1"О не самый щrформа~ныйспосо(j обрабоТЮI исклюЧения. по
СIЮJIЬКУ здесь вы не им~те ВОЗм6ЩНОСТИ получитьсодержателъную ИНфQрмацию
о ИРОйзonreдшей ошибке (1Jапример, Иl\.fЯ метода. GодерЖИМОе cтeнaВlill3oВOB ИJ1И
пd.JIЬэователъсКое сооБU!ение)_ Тем :не ]4енее, в С# такая КОFlCтpyкцшi вwзможна.
1/ Пepeюt_a,дJoIВ:aIDIе О!(IВете!1'ZSИВОС!1'И.
8'tatic l10id Main (stTing!! аrчs)
1
-
292 Часть 11. Язык программирования С#
try
(
11 Логика ускорения: ааТONоби.n •. ..
catch(CarIsDeadException е)
{
/ / ЧаС!1'ИЧНaJI обработка ОDlИбки и п.ренаправnение.
11 Зде~ перенаправn.еТСII ВХОДНОЙ объект CarIsDeadException.
11 НО МО*НО reHepкpoaa'l'Ь и дрyzoое ИСJCJШ~еиие.
throw е;
Внутренние исключения
Вы можете догадываться. что вполне возможно генерировать исключения и во
время обработки другого иСКЛЮчения. Например, предположим. что вы обрабаты
ваете CarIsDeadException в рамках конкретного блока
catch и в процессе обра
ботки пытаетесь записать след стека в файл ca rErrors.txt на вашем диске С.
catch(CarIsDeadException е)
(
11 ПОШl'1:'ка OT1CpNТЬ фaйn carErrors. txt на диске С.
FileS t ream fs = File.Open(@"C:\carError s.txt", FileMo de.Ope n);
..
Глава 6. СТР~КТУРИРD.ванна!l обработка ИСlf:ЛЮч~kий 293
catc:h (СjЭ.1.· IsDе..аdEхсерt·iОI1 е)
{
try
{
FileStrearn fS = File.Open/@"C:\c·a ,. rE·rrors.txt", FileJclode.Opt!n);
Блок finally
в рамках try/catch можнотаюке ОJiIРeд.eJlИТЪ1Iео6язат~Нl:itЙ блОК finally.
Зада:ча бnоХа. f1 nаllу - обеспечить безусл:овн.ре Вьщo.щieНИе HeКOToporo набора
операторов программного хоца. н:еза:виеимо "т налич;ия ищи OТCYТCTВ1m RСКЛЮЧ(i!
mm: (любого типа).. для npимера предпцложим, ЧТО .I;Ibl хотите всегда выключать
радио а:втомоБШIЯ перед ВЫХОДОМ из Ма i n ( 1, независимо от исключений.
catcb iCe.r!s.DeaG!Exception е)
{
/1 ОбрабООМСiL Ca:rrsDe~ception.
datcb (Мrgu:rnеntОutСП~angеЕ.хСi\рtiОD е)
{
/I Odрабduа ugщnentoutОfRJлgdxсерtion .
1
--
294 Часть 11. Slзык программирования С#
catch(Exception е)
(
// Обработка всех остальных искmючеНИЙ.
)
finally
(
11 Э'l!о ВIUlOJIИя:ется: ВС8%'да. НезёUlИСИКО О'l! ИСJC.JUOчеНИЙ.
myCar.CrankTunes(false) ;
I
ConsQle. W'r1teLi)~,e (ех. Мessage),
шегося без обработки. Более того. появится окно (рис. 6.8). в котором будет отобра
жаться значение свойства Message.
currSpeed • О;
! "1 Р
TroubIeIt_1O ТIPII
IGei oenёrafhe~ for this ехсерtioП.-- · --_._ - (О ) "
!
I
L--.. _ ____ ._ .. ______ ._ ______~.._.
el",e
-}
Если щелкнуть на ссылке View Detail (По казать подробности). появится дополни
тельная информация о состоянии объекта (рис. 6.9).
Резюме
в этой главе мы обсудили роль структурированной обработки исключений.
Когда методу требуется отправить объект ошибки вызывающей стороне. этот метод
соэдает. конфигурирует и посылает специальный тип System.Exception. исполь
зуя для этого ключевое слово С# throw. Вызывающая сторона может обрабатывать
посryпaюIЦИе исключения с помощью конструкций, в которых используются клю
чевое слово catch и необязательный блок finally.
....
Глава 6. Структу~ированнз.я о(jре.бот~а иоключений 297
I
npеИМУЩfXтватипов. ЦQДЦерживaюIЦИx "множесТ'sеНkое поведениеМ. В процеесе
Обсущде,нщr будет рассмотрен:и ряд смежных вопросов-в 'IаC':rНОСТИ. IIQдуч.ение
ин:reрфеЙсныхссъщок. ЦН8;Il реали3аЦ1-Ш и:нтерфеР...сов. а таюке иерарxnй интер
j фейсов.
! Част,Ь FЛЗВЪil будет посвящена рассмотрению целого рцда интерфейсов. Опреде
ленных в paм~ ffiИQmrотек базовых ю:raСC(Jв .:NEТ. выl увЦЦИ'rе. что определеНl:fые
t
!
lЩМИ цолъзоватenьсдие типы 'I'О:же МDЖl:lО встраивать в эти предопределенные' ~
Определение интерфейсов в С#
иано»reI-IИe материала этой главЫ мы начнем с фо,рмалы~ого щ:rределен:ия ТЙIIа
"интерфейс". ИНтерфейс - Это просто имеНОВailll8Я RDллекдия сеМ11нтИ<IеCЮJ свя-
3a.IпIых абоtnpwcrrtн.ьtx ' чтrеi:WВ. Эти члены опредeлmoтсл l';IНТерфейсом Б зависимо
СТИ от noвeдеНlЩ .которое МОДeJniрует дaнньtй интерфейс. Иитерфейс отражает IЮ
ведение. которое :может поддерживаться данным )'tЛ8.ссом'ИЛИ стру.турпй.
В рамках СИНТaRCйса С# интерфейс опред~щreтся е по1.!fОЩЪЮ ЮIЮчевого CJl0В3
interfac€. В отЛИ'4йе от дРулах ТЮ10В .NEТ, ;ин-reрфейCJЫ :викогд<!. Не уназывaю:r' б8 J
зoRыйассc (mшюч.ая System,Object) И ,ДЛЯ- ихчne.нОВНИКОIДВ ./ifеушi3ывaIOТся МOJ
дификаторы доступа (пос&o.льt<y все члены интерфейса H~HO считаются oт.кpы~
тыми). во1" пример пользовате.llЬCRОI;O юr:r:ерфеЙса. опреде.цеllllОro на.языке С#.
-
300 Часть 11. Язык программирования С#
Замечание. По соглашению имена интерфейсов в библиотеках базовых классов .NET имеют пре
фикс "1" (прописная буква "j" латинского алфавита), При создании пользовательского интер
фейса рекомендуется придерживаться аl~алогичных правил.
Реализация интерфейсов в С#
Чтобы расширить функциональные возможности класса (или структуры) пу
тем поддержки типов интерфейса, нужно просто указать в определении клас
са (или структуры) список соответствующих типов. разделив их запятыми.
НепосредственнPIЙ базовый класс должен быть первым эле.менmoм в списке, сле
дующим после операции, обозначаемой двоеТОЧl:lем. Когда ТИП класса получается
L
[лов 7. Интерфейоы и ICОJIЛе~ции ,301
Jreпосредственно из System.Object. можно укаэа.тъ ТОЛЬКО список .интерфеЙСов .
Щ)ддерживаемь1Х массам, ПОСКООЬ~ РРИ отсутствии явноro указaJmЩ компилятор
11 РеanиS&циR
IPointy.
public byte Points
{
get { return 3;
-lii1
,.'~ .. ~ ..
, ,.)
Интерфейсы в сравнении с
абстрактными базовыми классами
с учетом знаний, полученных в шаве 4. вы можете спросить, какова причина
въщвижения типов интерфейса на первое место. Ведь в С# позволяется строить аб
страктные типы класса. содержащие абстраятные методы. И. подобно интерфейсу,
при получении класса из абстрактного базового класса, класс тоже обязан опреде
лить детали абстрактных метОДОВ (если. конечно , произвоДНый класс не объявля
ется абстрактным). Однако возможности абстрактных базовых классов выходят
далеко за рамки простого определения группы абстрактных методов. Они могут
определять oTRpblТble. при ватные и защищенные данные состояния. а также любое
число конкретных методов, которые оказываются доступными через подклассы.
catch (InvalidCastException е)
{ COnSOle.WriteLine(e.Message);
Сопsоlе.RеаdLiле()i
i
., .
S.hap€[] s = { r,ew Hexagon(), r1ew Ci:rcleO, new TLiang~e("JDe"),
Л'еw Circle ("Jо;:Го"')} ;
for (int i = О; i < 6.1engt:h.; i++)
[
11 Н~OJOIИМ, Ч!1'О ба_о'- х,иасс Shape оnpед8.1U18'J! а6С!1".Р&МИIoIЙ
// чаев nraw (), ПОЭ!I'ОИу _са фОРIAI JlОryш Q'1'Обрua_ оеб••
$[iJ .DrawO:
11 х..о с: ••РIllИК8КИ?
i f (6 [i.] is lPointy)
Console. Wr-i.tеLlIlе ("~> Вершин: ! О) ", «( 1 Pointy) s [:L] ) .Po:Lnts) ;
else
CCJTislole.Wr-iteLiпе("-> {О} .!'5ез вершин!"/ B{iJ.PetName);
Предположим также. что две из наТnИX трех форм (Circle и Нехаgоп) сконфигу-
рированЪJ для поддержки этого нового поведения.
Замечание. С учетом общеязыковой природы .NEТ ваЖliО подчеркнуть, что можно определить ИН
терфейс на одном языке (С#), а реализовать его на другом (VB . NEТ). Но чтобы выяснить, как
это сделать, нам потребуется понимание структуры компоновочных блоков .NEт. что является
темой обсуждения главы 11.
/I Выso. D:Ж-iLV О .
Lihe ту Line = new Line() I
myLl.ne. Dra,w () ;
11 ВШlОII той . . реa.nи8АЦИИ Dr.'W 1> !
IDraw3D itmrаwЗd= ~IDr<!wЗЩ myLit\e;
itfJ;jга:.W З!:i.D:rвw() ;
с учето-м: того. что вы уже знаете о баЗОВ(i)М классе Shqpe и интерфейсе LDrаwЗD,
это выгля:.цuт так, как ~YДTO вы вызываете два BapJiIaНTa метода :D r aiW .() (один с
объеКТНОI'.O уроВЮI, а дР}'I:ой - е помощью интерфl;,йсвой ccblJlКl'i.). Однако вомnи
литО}') споообен вызывать oдgy'11 ту же реализацию и с :ЦО~ЩЪю ивтерфейса~ и с
помоIЦ'Ью OOЪeRТНOn ССЪ1Л1Щ. Dое.кольку абетрактный базовый :класс S'hape и:интер
фейс IDrаwз.D имеJOlГ(i)дшIа:ково внзвaнщ.rе ЧПСНЫ. Это может о:казаться проблемой.
KdrДallЫ ХО'1'ИТе. чтобы метод IDraw3D. Draw () предс'I"'cI1IJIЯЛ тип во в.сеЙ трехмерной
(3D) ~I(pa.c·e·. а не 11 неказистом .двухмерцом npедсташщн:ии переоnpеделенноrо ме
тсща Shape.D:r:aw ().
Теперь рас~М01JШМ родетвеl:UiyЮ проблему. Ч1'9 w.,лать.еели вам НуЖНО гаран
rnpовать. что метоЩ>J. oцpt'J1Meнвьre Дa.JЦIЪЩ m;lт~феЙсрм. БУдУТ .цос:ryпны ТОЛЬКО
310 Часть 11. Язык nрограммирования С#
Как видите. при явной реализации члена интерфейса общий шаблон выглядит
так: возвращаемое3начение ИмяИнтерфейса .ИмяМетода (аргументы). Эдесь есть
несколько "подводных камней", о которых следует энать. Прежде всего. не допуска
ется определять явно реализуемые члены с модификаторами доступа. Например,
следующий синтаксис недопустим.
/I Базовый ИИ'l'ерф8Йс.
public interface IDrawable
{ void Draw (); }
public interface IPrintable IDrawable
{ void Print(); 1
public interface IMetaFileRender IPrintable
{ void Render(}: }
п:nw.ы.. 11i'
"'bwfкa
БiI Methods
'. Pnгс
(',j Methods
• R~(1d<!r
Теперь. если некоторый класс должен поддерживать все варианты поведения, за
данные в рамках зтой иерархии интерфейсов. то этот класс должен выводиться из
интерфейса. лежашего в основе иерархии (В данном случае это IMetaFileRender).
Все методы, определенные базовым интерфейсом (или интерфейсами). автомати
чески переносятся в определение. Например:
Глава 7, Ищерфейсы и ЩЛl1ВКЩ1И 31 3
11 9TO'l' .x.na:cc ПОjЦ.цеpzивае!l'! IDrawable I IPrintable и lМetaFileRende'Z;.
PUbl.l"C cla S$ suреIImэ.gе : IМetaFileRe:nder
(
publi,c void Draw ()
{ 'сопsоiе .Wri t:eLine ("Вд.З0ва.", ndГ1ИКа, визуаЛИЗiЩИЙ. "'); t
pUblic void Prlnt()
1 Сшню.Lе ..Wr i teli rJ8 (1' ВЫВОД :на ПРИН'I'Е:'р. ") 1 }
j I ИСПQJJЬЗQSаиие ~рФеЙС()з.
5t,cёltic voieJ Main (strirtg [] argfJ)
(
81Jре.tIщаgе .5i = ne.w Superlmage () ;
/I Поnyчеиие IDrawable.
ID:ra'Wable H ..fDraw· = (TDraw~ble lai;
i tfDra'ol .1)У а.. () ;
COТilsole. RеаdLiпе () ;
фейсных типов
tl
vtЮ 'Нс сlJ!·З>! R~ "l \7;!< r,
(
p\JЬHc- IIlr.-1V",r, (,)
~
tI
После выбора нужной вам опции Visual stшtiо ~005 QFе~рирует nporpам'МНЫЙ
код ЗarдylliКИ (В рамках соответствующей имен@ванцой области программнОI'О
I\од~J. который ВЫ затем можете ИВМСИИТЪ (обра1'Ите вщuщние на ТО. ЧТО.IlQ умол~
'1:Ia.НJm) реализация ПРeдлaI:ает иcюnоq~mе System. E~c.€ptiQJJ).
n:а11lеэрасе 1FOIсеНiе.rё1,rсhу
r
I pttbli ,c clas!i MipiV<J,n
{
ICait
p u bli с Mi:rIi'Val', ()
r {
I )
#еПф- еqi оn
}
Но. нак это ни печально. компилятор сообщит вам, что класс Garage не реа
лизует метод GetEnumerator (). Этот метод формально определен интерфейсом
IEnumerable. находлщимся в ·недрах" пространства имен System.Collections.
ОбъеRТЫ. поддерживающие соответствующий варианТ поведения. декларируют,
что они MOryт раскрыть содержащиеся в них элементы вызьшающей стороне.
но есть и более простой :путь. ПОСКQЛЬКУ Т1Ш 'S'Iзtеm.Аrrау • .ltaR и Мноrие другие
ТШIЫ. уже реал:иЗОВaIi: в IEnu11Jerable и IEn,11Inerator. вы Moateтe просто делеrиpо
BalfЪ запрос н System.Array. K~ поназано НЙже.
Методы итератора в С#
в .NEТ l.x для того, чтобы пользовательские коллекции (такие. как Garage) до
пускали применение конструкции foreach в операциях, подобных перечислению,
реализация интерфейса IEnumerable (и, как правило, интерфейса IEnumerator)
была обязательной. В С# 2005 предлагается альтернативный вариант построения
типов, позволяющих применение цикла foreach. - с помощью tunepamopoB.
В упрощенной интерпретации итератор является членом, указывающим поря
ДОЕ возвра1Цения внутренних злементов контейнера при их обработке с помощью
foreach. И хотя метод итератора все равно должен назьmаться GetEnumerator ().
а возвращаемое значение все равно должно иметь тип IEnumerator. при таком
подходе ВЭllI пользовательский класс уже не обязан реализовьmатъ все ожидаемые
интерфейсы.
/1 Метод итератора.
public IEnumerator GetEnumerator()
r
Eoreach (Car с in carArrayJ
{
yield return с;
/I К!1асс Point.
риЬНс ~lёl~s POi11t
I
т
publi c int х, У;
public Point(in t х, int у) ( this.x = х; thls. y = у; )
public Point () {)
// Dереоnpедenение Object.ToString().
publ ic ove.rride string ToStr:ing ()
{ retur:n string .Fo rmat("X = {Ol; у = { 11
ОО
, х, У ); }
/1 e-ооЦ· o&.e~a.
COhsole.W.r iteL·ine (р3);
Console. iilri t:Е;Liле (р.4);
Пример кnонирования
Предположим. что клаСQ 'Б'оi ·пt СQде'рЖИТ член ссылочного ·TIJUa. с именем
РQiЛtDеSсri.рtiоп. обеспечивающий поддержку ~панятн()ro" имени объекта Point
и ero.идеFi':rИ:фикационного номера в.виде System.Guid (ecmlY вас нет OIlЬJТв, при
менешm сом, знайте. что GШD - rлобалъно унивалъный пдентnфикатор - Э'ro
стаТИC'rИчоски уникальное 128-раарвдное значение). Вот соответствующая реали
за:щш.
p).1blic PO.lnt;Description ()
J
-
322 Часть 11. Язык программирования С#
При этом для учета НОВЫХ элементов состояния в самом классе Point следует
изменить метод ToString (), а Та1\Же операторы определения и создания ссылоч
ного типа PointDescription. Чтобы позволить ~внешнему миру· указать имя ДЛЯ
Point. можно Та1\Же модифицировать аргументы. передаваемые перerруженному
конструктору.
Не забудьте о том. ЧТО вы еще не обновили метод Clone () . Поэтому при запросе
клшm:рования объекта пользователем с помоЩьЮ данной реализации все равно бу
дет получена поверхностная ("почленная") копия. для примера предположим, что
мы обновили метод Main () так. как показано ниже.
static void Main(string[] args)
(
Console.WriteLine("***** Забавы с ICloneable *****\п");
Console. WriteLine ("I<лонирован рЗ, новый Point сохранен в р4") ;
Point рЗ = new Point(100, 100, "Jane"};
Point р4 = (Роiпt)рЗ.Сlопе();
Сопsоlе.WritеLiпе("До модификации:");
Сопsоlе.WritеLiпе("рЗ: 10}", рЗ);
Console. Wri teLine ("р4: (О}", р4);
p4.desc.petName = "Мистер Х";
Глава 7. Интэрфейсы и ~f)лпеIЩИИ 323'
р4.х = 9;
CO,D sole.WriteLine ("изыенены- р4.dеsс.p€,tName и р4., .:Х" ') i
·С O l'l-S о 1е • Wr i teL 'I..ne ("ПоСле :МQд:ифИI<:а1(ИИ~ О ,) ;
Солsоiа,Writ;еLiпе '''рЗ . : (О] 1', р3);
.Consol е . Wri teI.ine ( .. р4: (О )~I р4);
Еелй выполнить ПРИЛОiЖе}ЦIе тe:neръ. ТО.ВЫ увидите (рис . 7.9). ЧТО возвращен
ный методом Clone () объект Point действительно I<DIrирует .:мlyТpеЮlя.е ССЬJЛоч.
вые члены-переменные:гипа (обратите внимание на то. что эдесь р3 и р4 Щlltеют
СВ(jИ yникв.;n.'НЫе имена) .
Итак. в том случае. Rогда класс или структура содер)Кит только ' ТНЦЫ. ха
рю(т.еризуемыe значеюlЯМй. лучше реализовать .метоД CIOlle (.). использующий
MemberwiseCl o.ne (). Однако в том сдучае~ коtда ПOJ1Ъ:ювате,лъсюm ТИП содержит
СCЬL1l0ЧНЫС :rипы. :вы должны создать HOB:t>.Iй тИП. П,PJ1ню,.twoЩИЙ :(Jo вющ:ание Bt:e
ч:ле:ньt-переменные ССЫJ!очн:огоnшa.
-
324 Часть 11. Язык программироаания С#
11 Р811.JIИ$&циа ICCllllpar~],. ••
int IComp.arablce . CompareTP(object obJ}
!
Car~emp = (Car) obj;
if (this. car!D > temp_oar~p)
retlJ.rn ~;
i f (this.c.arIP <t.emp.carID)
e lse
re t-ur.n О;
326 Часть 11. Язык программирования С#
Любое число , меньшее нуля в данном порядке сортировки текущий экземпляр размещвется
до указанного объекта
Любое число, болы.uее нуля В данном порядке сортировки текущий экземпляр размещается
после указанного объекта
Теперь, когда тип Car "умеет" сравнивать себя с подобными объектами, вы МО-
жете записать пользовательский программный код следующего вида.
i
Глава 7. Интерфейсы .и коллекции 327
Инте'рфейсы И3 простран,ствэ
l1м:ея System,.Co:llecti:ons
ВУй'lч€€'me СЩ4(JГQ ~Т:Ц:НОЩ ~paA(O&feт~ 1'ИП s~~'.Al;'J:,gy,.
В Щ~~ :3 бьJp:rд IIOEa,g;uro, ЧТО 'У..л.аJX Sуэt1О'l!! ,Arr,,-'{ npеддаГоЗ.е'l цe.,lТblii рад С!)ОТ'
~.YJOЩ~ »G<},МЩ'RВОС~Й (1'a1fn':1Щa ,И!I{В«;РТНРОWНfiе. ОQРТlilPQЩ<а. очв~п:а 11
tlе~'!<J'IJ[cэ;t~Iе). Но lиаее ,'АУ r ау дм.еет С:В!Ж' о:гр(l.'ЮfЧ~,1-:ЦЩ. :n IlCЦJБОiQее важщ.~:,0~
нs: я;I\ЛJ!!;('WJt Н~OSМOЖflо(,n. ДIm:uтче(:IrOГI:>, I1ерео~дещ~ШI~ pal1Jl4ep0J!l' nPJi!i ДQ
бщlле--cliЛI 11 У.д:ai1rеt:I,ИП Эn€МtЩТФ'1i.'. Еt::J,Ти ДrnJ ~eJ'U'UI Тl'ЩйВ аеобхщmм БQдее ...~
JCИЙ~' 1'toa:rdhlep, лучщ~ JI:t',До~ов:ать ТJЩы. Onp,t'i,te,zr€il'JВЪte В :ПРЩтpa1IС'fflе ~Щ!!
$У'тtе;щ. С:оl1~,,(З t ±dl'il S(I;IJЩ, .в (Щ:O"fвет(,"1'ЩfИ С Р~К,t;lмеFW;Щ~ r,(I'aвbI l'O, щ1 пrю
с':tpaщтв& имев ,S:,'[:Stem.~Q;Q11"ctiQn;S .:Gе:пе:zr1:~}.
Лрострm.tМ'):Щ имц:, SystO!;1Тl:,Co1l!ectiQ;us Ф1:l;реде~т ЦfC.зnШi: PfЩ и:нт~феЙ~Dq
[в. ~Ke;тOPыe :И:-9 Н1Юi УlIЩJ' ИUIlQ,льзона:писЪ в lWи:м:ер~ Э'wй ГШUlЫ).. ~ u:pавиn'О.
WIOreR"ЦИliI' ВШtесов pew:mэyет 9ТИ Я1Нl1еptf!eИСJ>l tЦJ~ 'ТOГlil~ 'Ч1'O(j'Ы 'ofreслечиlГ.Е;. ДQC'I)'П
.k cnPt",МY е(Щ~ржцмому, В 'Тз,бд. "1 .2. цр~"СЯ, QnИС;WUЯ ~YOB~ ИJl'терфеЙаQВ.
't:1Di«)СЮЦИООJ}3 ~ .IIЩJIil:elЩRПJ'.t;.
......------Dt' =- а
1j) j<;)-_ _ _ _ _- '
.-- -- - ~ -- _.- ..
~ . - - - -- - ---
I=odo!Ptovlder
. ,. !!' I I' ~
I ~
•
:i';.'!
~ __:.!
Интерфейс ICollection
Интерфейс
ICollec tion является простейшим интерфейсом пространства имен
System.Collecti o ns в том смысле, что этот интерфейс определяет поведение,
подцерживаемое любым типом коллекции. По сути, этот интерфейс обеспечивает
узкий набор свойств, которые позволяют определить: а) число элементов в контей
нере; б) защищенность цепочки контейнера: в) возможность копирования содержи
мого в тип System.Array. Формэльно ICollection определяется так, Jtaк показано
ниже (обратите внимание на то. что ICollect i on расширяет IEnumerable).
public interfac e ICollection : IEnume rable
{
11 Член IEnumeraыl •. ..
int Count { get; }
b ool IsSync hronized [ get;
object SyncRoo t { get; }
v o id CopyT o (Array array, int index );
Интерфейс IDictionary
Вы, возможно, знаете, что CJЮварЬ- зто коллекция, обеспечивающая поддерж
ку пар имен и их значений. Например, можно построить пользовательский тип ,
реализующий IDictionary, в котором вы сможете сохранить типы Car (значения)
с возможностью их последующего восстановления по IO ШIИ petName (это примеры
имен). Интерфейс IDictionary определяет свойства Кеуз и Values, а также мето-
Глава 7. Интерфейсы f1 коллеЩI1И ЗЗ1
Интерфейс ID:ictionaryEnumerator
При внимательНQМ чтении вы моти замеТl11'Ъ. ЧIТО IDiсtiопату.GеtЕhuд\~rаtот 1)
ВQзвращаетэ;кземnляр lDiсtiРDаrуЕщunеrаf..оr:'.Т'ип !Dict.ionaryEnurnerator-
это строго ТЩЩЗ0Вa.ннъr,й. нумератор. рас1DИpШОЩИЙ IEIJUmer:at:or путем добавде
ниn CJlедУЮщей фую:щио;надьиой возможности,
Интерфейс IList
ПослеДШIМ из :клюttевых Иftrерфейсов Sуstеm.СоПесtiОJ1S ЯБЛНется I'n-rrерфейс
IList, который обеспечивает ВОЗМОЖnость вставки. Уд8.J"'Iения п индексирования
элемt".RТQв контейнера.
Реализуемые
Класс Описание
интерфайсы
___ _ __ _ _ __ _ _ _ _ __ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ _ _ _ ь~
Глава 7, Иl:IТерфейсы ~ КОМ:~КЦИ~ ззз
Член Описание
try
{
console. Wr i teLine ("Первый элемент' : {О}". s t ringStack.. I?eek (j );
ЗЗ6 Часть 11. Язык программирования С#
c atch(Exception е)
{ Сопsоlе.WritеLiпе{"ОШИ бка: {О)", е.Мезsаgе);}
Пространство имен
System.Collections.Specialized
Кроме типов, определенных в простран:стве имен System.Collections. библи
отеки базовых классов .NEТ предлагают набор более специализированных тm;rOB ,
определенных в пространстве именSystem.Collections. Special ized. Например,
типы StringDictionary и ListDictionary обеспечивают ~стилизованную" реали
зацию интерфейса IDictionary. Описания основных типов класса из этого про
странства имен предлагаются в табл. 7.5.
Тип Описание
Резюме
И:Erreрфе'ЙС ,мo~o tпrределить. как имеf{ОВанную ./{QЛJIelЩИЮ аОСl7'ipаюnн.ых чле
НОВ. ВJ!Иду' тоro. что jffiтерфilliс не преДJ:Iзтает деталей реализаЦиИ. ан обычно рас-
сматptmaется. как, ~риант ПQБедeIOfЯ.. воаможноro для двв.нОТО типа. При реализа
ции о;цноro и 'того же ин:reрфейса .в песJtолыtlц ЮIассах вы llOд:учаете ВО3мОЖ:ноеть
обращаться с Сouтве'ГОТВУК)lЦИМИ ТИШiМJХ о,дЩi'авово ,.~1ГO называется интерфейс
ным ПО:ЛИ)fорф1;Iэ;мом).
Для определе6"~Я }]о.вых интерфей:~ов В, С# предла"Fается клюЧевое СЛОВО
lnterface. Любой тип может nодде}!)живатьстолько щперфffi:iсОВ. акО;Т1ы(о необ
ходимо • .цyжFIO талыш ухазать их в сIIИCJte определешш типа. разделяя 3arutт.ыми.
1/ Oo.rnpUKa ~ АЬoutжоВlow.
i f (10 = maxSpeed ~ cUirrSpeeq.)
{
foreach ( IEпgitiеЕvеп:ts е in ,С} ±~ntSilJks).
е • Ab01.1tTQВlow ("OCT-,ОрG1IlliO , ! Могу сломатрся.!");
// Создание объехта-npиемииха.
CarEventSink sink = new CarEventSink();
I ИН'rерфейсы событий могут быть I10ле-.зны и тем. что m-т 'МЦСУТ ИCIJоль:юваться
с люб:ыми ЯЗJ:dКами и любыми 1JШ1'];фQрj..raми (.NE.T. J2EE или КШШМИ-ТО IIными'.'
1I0Д1I.ерживаюЩJiIМИ npоrраммирсшаНие на оонове интерфейСОВ. Однако ~()фйЦИа:ль
ныК' nP0ТOKQJI событий задает rтa:тформа .NEТ Чтобы понять вву-трeнsюю архи
тектуру обработки собы;тИЙ. МЫ начНем с обеуждвния роли Tt!lJa делегата.
Замечание. В отличие от указателей функций С(++), делегаты .NEТ могут указывать на статические
методы и на методы экземмяра.
ет. Вы убедитесь, что в .NEТ Framework каждый делегат .NEТ (В том числе и ваши
пользовательские делегаты) автоматически наделяется способностью вызывать
свои методы синхронно или асинхронно. Это очень упрощает задачи программи
рования. ПОСRОЛЫСУ позволяет вызвать метод во вторичном потоке выполнения без
явного создания объекта Thread и управления им вручную. мы рассмотрим асин
хронное поведение типов делегата в ходе нашего исследования пространства имен
Определение делегата в С#
Чтобы создать делегат в С#, вы должны использовать ключевое слово delegate.
Имя делегата может быть любым. Однако делегат должен соответствовать методу.
на который этот делегат будет указывать. Предположим. например, что нам нужно
создать делегат с именем BinaryOp, который сможет указывать на любой метод,
возвращающий целое число и имеющий целочисленные входные параметры.
~ "'A,NIFEST ~
,. • 5irф1eD.~
~ .~.t",prap_
,. а
, ~ ..:ja$"pUb"c ~Q ~n'i_le:d
~ ~1'fds Г_nrlib~ЯеI1\.м...Jt",.,.ф~
• ,ctol: \':IIld(оЬ1е<t,пж,'«I 1rIt) ,1
• вegл1n1'bk81 Wss,Гmsoortlb1SYstsrn,IAs)'nCRмUlt(II'ItЗ2'{i '
• E~nl'Oko :'i1t32(L'-s, [mscttli:>JS.ystem .!A<Yf'd!IISIA:) ;i:1
• !n~~ : itЭ2!.iJ1tЭ2.iht3ZJ '
,j, 8 S~, Program,
rseiгlaliz,a:ы1 е J
P!дЫ~ ~ §lI:H~t,~acb t:.la!3s huHi-О.s$'t[).е-]еqRt:е ~ t'le.]egll'J:e
!
li~_
РlЗbНс: >8.2aledomin-i(le Dеlе,qщtэl1 r;eцnш>саt.w.rй,i:;;1r(}i
/IП~
pii~~te rntrtr _~nvoo~~i~n~uunt;
~t"i y«teob-1 ~(.,t _ u\;ющ.1r.!L('j:аL:ist i
}I
11 Свойства
public Methodlnfo Method { get;
public object Target I get; )
namespace SimpleDelegate
(
11 Этот деnеrат может указывать на любой метод,
11 QPининааций два це.пых значении
11 и возвраща ....~ цепое значение.
public delegate int ВiпаrуОр(iпt х, int у);
r:;lass .PrQgram'
j
static void Mai.n (string 1) args)
I
Сн:ова ~брати.те 8н:имaIще: на формат д.елегата' 1;11 па ryOp, которьЩ может yкam.т-
ватъ на .ttюбоЙ ме1'ОД. лринимаюIЩiЙ- ЩJа целых эна-чен;ия; и во3,Вращающий целое
ЭUAчение. ИТaJC. МAI СО3,дЩIИ КJЩСС с вм;ен!Ш SimpleMath, ОIlpfЩедяющий два СТЗ1'И
чееRИX t.reтoдa. которые (как неожиданно) соотве:тЩ1lуют шаблону, оnpеделеннi:Jму
делегатом БinаrуОр.
Чтобы добавит~ целевсЩ мещд в де.дегат, нуnщо д:рост{) , цереддтъ имя зтo.ro ме
тода KOHCl'PYКTOPY делеГЗ'l:а. Тогда вы оможете выэ;вan. YJЩЭанНый -ЧЛен с помощью
СИНТ8КСИ',lесJCQЙ IЮ!fС1'рУЦЦии,. подобt!\QЙ прнмому вщову фующии.
С учетом того, что делегат BinaryOp может указывать только на методы. при
нимающие два целых значения и возвращающие целое значение, следующий про
I
граммный метод оказывается некорректным и ком:п:илироваться не будет.
Если иэменить метод Main () так, чтобы он вызывал этот новый вспомогатель
ный метод, то вы увидите вывод, покаэанный на рис. 8.3.
стого сложения двух чисел. Но этот пр:имер раскрывает npинцип:ьr работы с J:ИП,a:
ми делегата. Д1I.Я построения' более реадьного примера: мы м:рлифиццрущ 1;'ЩJ Ccrr
T8I(, чтоб};! он I10СЬLjJ8Л сообщения Exploded и .AbolJtToB1QW через д:елегаТJiI .NEТ. ~
не через ПО11Ь.зоватеJIЬCКИЙ 1UiТерфейс обратного вызова. Кроме ОТIШ38 ОТ реац:иза
ЦИИ IEngineEv:ents, :мы должны выnоmmть CJ1еДУlOщu:е шarи:
• обновить метод Acceler ate (), чтобы иметь возможность в подходящей ситу
ации обратиться к списку вызовов делегата .
Обратите щrnмание на то. что в этом при мере мы определяем типы делегата
непосредственно в рамках типа Сат. Если исследовать библиотеки базовых клас
сов. то станет ясно, что определение делегата в рамках типа. с которым он обычно
работает. является вполне типичным. В связи с этим, поскольку компилятор пре
образует делегат в полное определение класса. мы здесь фактически создаем вло
женные классы.
1/ ВО'1'-:ВОТ сnомаeo:rся:?
if (1О= .rnaxSpeed - currSpeed <1<& д.lmоstDеа.dLis"t ,!= п:иl1)
{
аlrtюst.DеаdLis-t ("ОС'I'Qpожно! Могу СЛОМ2ТЪС:Я I "J ;
Здесь следует отметить только то, вызьшающая сторона задает значения чле
нам-переменным делегата с ПQМОlЦЬЮ вспомогательных методов регистрации.
Кроме того, поскольку делегаты AboutToBlow и Exploded вложены в класс Car, при
их размещении следует использовать полные имена (например, Car .AboutToBlow).
как любому конструктору. мы передаем конструктору делегата имя метода, кото
РЫЙ нужно добавить в список вызовов. В данном случае это два статических члена
классаProgram (если вложить указанные методы в новый класс, это будет очень
похоже на тип CarEventSink из примера Eventlnterface).
ивание. Чтобы разрешить групповой вызов для типа Car. можно обновить методы
OnAboutToBlow () и OnExploded () так, как показано ниже.
c lass Program
.ma.xstack 8
ldarg. О
dup
ldfld сlаsз 'CarD~lE!gate. Са г/lI..Ь.сщt'l'vIilow CarDelega:te .ca.r: .:i'!lrn{)jзt;DeаdЫst
ldarg.L
call clas8 [msссэ%:liЬ] System.Dalegate
r'm$cor~ib] System,Delega'te: : СФПlbinе t
class [mscorl.ib] Sузtem. Del~gate,
class [mscorli.b]Sy.stem.Peiegate)
са:ЕЙ.сlаS$ Са rDelegate. Саr/.JlliоutТQ'ВlФ.w
sttld сlаэs Сат~lеgаte.СаJ7JА1Юllt'rоВl'0>11 CE!tDelegate.Car:::
.almostD€adList
ret
1Сл:ас(: Delegate определяет та&же статичес:кий метод Remove (J. коrroрый по
аволит ВЫ3ьtвающcii: стороне динамически удалять элементы из СUИCRа Вhl<JOBOB.
ЛеtRо догадатьСя. ЧТО в c1f разработчики MOryT ДJ1Я этого ИСIlOЛbзоватъ перегру
Ж~ННУЮ операцию - =. Чroбы предоcтaDИТЬ ВЫ8ывшощей стороне ВО3МОЖl-ЮGТЪ не
привязывюъсл к 060знач:е:ниям AЬou.tToBlow и Exploded. можно Добавить в ntn
Сат след;yroщие вспомогателънъrе методы '(обратите внимание на операцию - =).
:p11l:JHC с:lа$.Э Сат
j
11 'УДaJIeJIИS эnенеит.а И3 оаи:сжа Эl$оэоа.
ppblic \fOicl Rel11OveAJ:H:;JutTc;H31ow (·AbQll"t:ToliНow сliепtМеНюd)
{ аlIlюstDеаdList -= сl ieТJtMethod; I
.. тпах:о tack. 8
ldarg.O
dup
1dПd class carDelegate, Ca:r/Abo1Jt1'OlHow CarDelega,t€.. Саг: :iJ.lmos,tDeadLi5t
ldarg.l
356 Часть 11. Язык програММJ.1роваНИR С#
I
Глава 8. Интерфей~ы об.Р1l1нога вызова, деяегаты 11 собl:llТ11,R 3-57
замены шин (sIЮll1dR'оt.аtе), 't:JтofiЬL DОЭЕОJIИТЬ ПОJThЗователю, объеъ."ТЗ взаимодей
етвовать с этими НОВЫМИ данными соСТоmш.я. дл:я Сах опредe.mпoтс.я веобхОЦИМ1i1е
дополп:ителънъте овойства, и обновляется KOнcrpy:ктOp. Вет как BыI'.!llIдw1' соответ
ствующим образом модифицированный программны:й код.
lsDirty ; washCar;
s,hQu.ldР.вtдtе = 1iotat:e'I'iresl
функции, которые принимают этот делегат в виде параметра. для примера предпо
ложим. что у нас есть новый класс, которому назначено имя Garage (гараж). Этот
тип поддерживает коллекцию типов Сат. содерЖaIЦихся в System.Collections.
ArrayList. При создании ArrayList наполняется типами Сат.
Кав и в случае lIЮбаго деле;rата, при вызове P:roci?asCi'if s (). мы должны У1са
~a1Ъ имя метода, который. обработает запрос. Ha:rrOMI-IИМ, что такой метод мщкет
быть или tтaтичеckИМ. ИЛll методом экземпляра, для примера предположим, что
Б пачеc::rnе таното меТdда буДут исnoл:ьзоваться ttJrel-IЫ экземпляра новото класса
BerviceDepartment (отдел те:хни'1ecRоt() обслуживания). :которым назначеНЪ) вме
па ИasВ'Са!' () и R€Jtatelires ( I ' Обратите внимание на 1'0. '11'.0 ЭТИ д)щ метода uc-
1IОЛЬЗУЮТ новые СВОЙ:ст.ва Rotate и Oirty типа Car.
/I ЗIro'i' JUtacc опредeJIие'!1 Me'1'O~, ItO!l!O~ БV'Д>"» 1w9ыв~сяя
11 ~ОИ Car. carDeIeqate.
pl1blicclass Servi сеПераr.tmелоt
{
public void ·Wasbl~ar (Саь: с)
!
if(c.Dirty")
CO:nSGle. Wr.i t 'e Lirfe ,( "Моем машину") ;
el.se
сопзоlе. Wri te1.ine ("·Зт.а машина уже (юмыта .• '. !'');
g.ProcessCars(new Car.CarDelegate(sd.RotateTires»;
Сопэоlе.RеаdLiпе() ;
L
Fла,вз8, И~IТЭРф!:!ЙСЫ обраТflDГО ВЫЗОВЭ, делегаты и соб!JIТИЯ 361
foreach ( C~T с in thеС~rэ1
proc(cJ; IIproc(o) => Se:r:viCeDSpaztm&nt,WashCaz(c)
11 Помеюшъ JIIщ!ы.
g. !?тосеЪ1 sCar s (л€!"w Сат, CarDelegate (зd. Rot.dteTi!l:es) ) ;
Ковариантность делегатов
к этому моменту БЫ должны чувствовать себя БOJ,ее ynepetrno при создании м
использовании типов делегата, Перед тем как перейти ,Е иэучению mпrтаксиса со
БЫnIЙ II C,:ff, мы раССМQТРИМ новую возможность .NEТ 2.0. CRЯэанную с делеrатами
и обозначенную термином кoвa.puaHm.нocmъ. Вы могли обратить внимание на то.
ЧТО все делеrаты. созданные нaJ.\4И ДО сп пор. указывали на методы. воз,йращаю
се las's P'[;ogram
1
pl1Dlic delegate Car Ob,tainc:ax'Delegate();
Пока что все выглядит прекрасно. Но что делать, если мы получим новый RЛасс
SportsCar из типа Car и потребуется делегат, который сможет указывать на ме
тоды, возвращаемые ЭТИМ новым типом I<ласса? До появления .NEТ 2.0 в таном
случае вам пришлось бы определить новый делегат.
ObtainSportsCarDelegate targetB =
new ObtainSpo rts CarDelegate(GetSportsCar);
SportsCar зс = targetB();
Console.ReadLine();
class Pr o gram
I
Соnэ~l е. Wri t .e Lin.e (".... * "*" Ко.В'df'иа.н'!'иос.~ь делега.ТQВ *" * 'k*\n 11 ) ;
Со'бblТИЯ В С#
Делегаты оказ-ываются QЧ't:Нb ИErreресн:ыми КGJИетрyщ:wлм:и; с ТОЙ ТОЧJm ЗРeJШЯ ,
ЧТО ойи предостав.ляют возможность реализовать двухсторо;ннее ВЗЩlМОДЩfствие
междУ объект3.Т\.IИ в пaм.wrи. Одшшо. :и вы с 'ЭТИМ сог.п~~;ИТ~Щ" работ~ с делеrnта~
1IШ напрямую преДn'J.!Iarает :ВВ"Д больших по объсМу ша6лOНl{blX фрагментов про
гpaммнoro кода {anpеделени.е де:л.егата.· объявление членqв-пере,меЩЩdХ, СQЗдание
щ)лъзовзТелЬСкихметОДОВ регис'tpа'ЦИИ и отмены регистрaцJfИ}.
Поскольку возможность обратного вызова оБЪeIcrов дрyrим 06уектом ЯБ.lЩетС'л
очень полезной, в С# п;ре;цл.агаетСn: СПециальное ключевое CJJfJBO ~ve:nt, ПОЗБОЩI'
ющее :мипимиmrpовать неудобства прагрaмNIИста, связанные с неJ;rосредственцым
nрименевием делегатоВ. при обрабоruеюnoчевогослом ~vent кОМПШlЛтор' ~TO'
ма'Гически создает дrJIЯ вас методы регистрации и отмены регистрnцlЩ. '" 'Ii~e
'ЧJIены:~перемепные. неоБХодимые ДIJй вшиcro типа делегата. КЛючеВОе· СЛово €,,"ent
можно наз.вать СИН'1'аксичеСJЮЙ ~Jroнфеткоif'. позволяющей экономить BP~ IlpJf
вводе программного кода.
'З8М8"Iвнме. даже при ИQПольэовании в сit"JWIQЧВВQГО слова event !:!ам все мвiЮ придется ВРУЧ,
ную QпределЯТI:1 связанные с делеrёfТОМ ТI<1[1Ь1'.
364 Часть 11 . Язык программирования С#
p ubli c c la ss Car
(
11 Этот ~eneraT ~аБОТАет в свкэхе с событиими Car
public delegate v oid CarEv e ntHandler(string ms g);
11 Об'Ъ8ХТ Car ко.ет nocыna'1'Ь Э'1'И соБытя•.
p u ыcceve nt CarEven tH an d ler Ex pl o ded;
public event CarEventHandler AboutToBlow;
else
cu r rSpeed += deltai
11 Вот-вот cnокается?
if (10 == maxSpeed - currSpeed
&& Ab o utToBlow != nu ll)
Глаllа 8, Иflте:рф&йt:'ы '(jБРJl;НОГО вызова, деnега1'ы и СDб.ытия 365
Abou,t1QBlQ~1 ("Qс~орожн.о! Мо,гу 'сломаться 1") ;
/ / J;IO,!I!8' в ое ОХ: !
if (cur.rSpeed>= I!laz'SрееЩ
саУI s'Dead ~ true;
~lse
C~mS,Qle. WriteLine (~->ОJ:rrSраеd = ! О}", ,C'U,rrSp,eed} i
,JltdJ't8 tar::k В
lde.rg .0'
lda-:rg.О
ld:f ld class CarE~!]ts .·Ci1l.r;/C.ar,ENe!] t:Нandleт Ga·d v-ents. Са:с: :AbQ!1tToBlow
J.ctarg.1
call сlазэ [lnso<r3.rli1J] S.ystep1. Delegate
[mscorlibj System.Dele_9 ate: :Combine (
cla 53 [m,sco1rl iыl $ys,t6m. Delegate,
class [шзссrliЬ'j ayst'em.Delegat.er
castclass Cii\·rEven ts. СаrJСаrЕV2ТJ,tНаш:!lеr
st.fld с lазэ CarE\r€rnt~s _.Car iС arЕvелtНan,d1еr ' ёаtЕvер ts . С<3,Т; ;.AbQutTQEloW
r e-t
.maxstack 8
1darg.O
1darg. О
1df1d c1ass CarEvents.Car/CarEventHand1er CarEvents.Car::AboutToBlow
1darg.l
са11 class [шsсог1iЬ]Sуstеm.Dе1еgаtе
[mscorlib] System. De1egate: : Remove (
class [mscorlib]System.Delegate,
c1ass [mscor1ib]System.Delegate)
castclass CarEvents.Car/CarEventHand1er
stfld c1ass CarEven ts.Car / Car Ev entHandler CarEvents.Car::AboutToBlow
ret
11 ОбъеК'1'RaяIIеременн&Я. ИмиСобъrrия +=
I1 new Соотве'1'СТВYDЩИЙДеnега'1'(вwзываеиаRФУНКЦИИ);
Car.EngineHand1er d = new Car.EngineHand1er(CarExplodedEventHandler)
myCar.Exploded += d;
...
Iлава 8. Интерфейсы обратноrОВblзова, Аелегаты и cuбl>ПИ!j 367
11 ОIS'J.8кщ~~~. ИИJrСоБJ,Щ1ИR -'= О~Д~er'a'l'а.;
1JlyCar . ExpCLaded -= d;
clas$ l?rogram
(
static void blain (St.ring[) a:!."gs)
{
СОП'S<JDlе .• Wз::itеLiпе ("**".** ООDЫТИЯ "1i"~*");
Саг ci =
П
new Саг с э1 ugВug , нJO, 1 О) ;
/ / Ре:I'ИC'ЗIJ?ЗЦЮI обрЗбО'Х'ЧJщQ8 ооБШ!ИЙ.
c1.AbOlJt'roBlow += l1ew Сах: .саrЕ·.... еDtНапdlеr (Ca.rIsAlmostDoamed);
cl.lI..houtToBlow += I"!ew Саг.СагЕvеntJliЭ.ndlеr (Сал:;АЬоцtТоВlоw);
Саг. CarE)\7~tH[;llicller d =о ]')~W Car. CarEve!JtJ-I111),:ilеr (СаrЕхрlоПеd).;
cl. Е:ирlоded += d;
После нажатия клавИIIIИ <ТаЬ> будет предложено ввести имя генерируемого об
работчика события (или согласиться ИСПользовать имя. предлагаемое по умолча
нию), как показано на рис . 8.8.
i
!!
Рис. 8.8. Формат целевого объекта делегата IntelliSense
Эта возможность IntelliSense доступна для всех событий .NEТ из библиотек ба
зовых классов. Данная особенность интегрированной среды разработки позволяет
разработчику существенно экономить время. поскольку избавляет от необходимо
сти искать по cnpaв1te .NEТ подходящие делегаты (и выяснять их форматы) для ис
пользования их с конкретными событиями.
"Разборчивые" события
Есть еще одно усовершенствование. 1tOTopoe можно внести в наш пример с
CarEvents и которое соответствует шаблону событий. peRoMeHдyeMoмy разра
ботчиками из Мiсrоsоft. При исследовании событий. посьтаемых данным типом
из библиотек базовых классов. вы обнаружите. что первым параметром соответ
ствующего делегата является System.Objec·t, а вторым- тип, произвоДНый от
System.EventArgs.
Аргумент System.Object представляет ссылy на объе1tт, посьmающий событие
(такой как. например. Car). а второй параметр представляет информацию о соот
ветствующем событии. Базовый класс System.EventArgs представляет событие и
не передает никакой пользовательской информации.
rfl8вa в, ИН'Fерфе~IGЫ оБР~ТНt}го вызова, делегаты 1.1 СDбlJlТИЯ 369,
public cla5~Eve~L~rgs
(
publi .c sta'tic !еа~щйу S.уstеm.Evел·tАгg·s Eropty;
риыl ic EverrtArg-.s ( ) ;
, {
I J Eomr
if
~a c:.nои~ась. , :r:oеиермрve'l'СR соб2mе ~lll)ded ,
(са J;:! sDea'd)
{
Н( Е:хр 1 oded'! "" !'1I'lJ Н:)
Exploried(this(
леw Cii-хЕvеп tAr9'З (' "Извиниmе f машина .сЛО!ol<lЛdСЪ ••• то ) ) ;
els-e
.. ,
АЬо·ut'ТоБ10.W (thiS,
new CarEver!tA1:'ge ("Ос:rgРОЖЕЬ! МЬГ'У СJlОМЭ<1'!>СЯ! ,j)) ..
370 Часть 11. Язык программирования С#
С точки зрения вызывающей стороны, все. что нам требуется. ,ак это оБНОБ.iIе
ние обработчиков собьггИЙ. чтобы иметь возможность принять поступающие пара
метры и получить сообщение через доступное только для чтения поле. Например:
Car с = (Car)sender;
c.CrankTunes(false);
Анонимные методы в С#
в завершение этой главы мы рассмотрим некоторые связанные с делегатами И
событиями возможности .NEТ2.0 через призму возможностеЙС# . Для начала об
ратим внимание на то, что в случае, когда вызывающей стороне требуется осу
ществлять прием поcrynающих событий. необходимо определить уникальный ме
тод. отвечающий виду соответствующего делегата.
class SorneCaller
Если немного подумать. то станет ясно. что такие методы. как MyEventHandler () .
редко бывают предназначены для вызова вне вызываемого делегата. А с тоЧI<и зре
ния продуктивности слишком непривлекательно (хотя и не запрещено) вручную
определять специальные методы. которые вbIЗhIВаютCJl объектом делегата .
Глава В. ИнтерфeJ1:сыоб:ратноуо .8'ЫЗОJ3а, делеrаТhl и ,событи*" 371
чтобы разре.шить эту прvблему, 1'fШеръ позволяется ассоциировать делеl~ат :не
посредcr:вeШI0 с блоком операторов программн.оI'о кода при реmc-rрации собыnm:.
Фа'рмаlIЫIO таком прогр~tй: код назы:ваетС:Я a.нoНILМН.ым мemoдo;>;l. в качеетве
ил.m:оетраЦИl-1 ба30вогос~нтаксиса рщ::смотрите сле.цующ:ий метод Ма i11 J). :в :КОТО
ром : посыаемыe 'rИШIМ Car событц;н обрабатываютсв с помощью анонимных ~eTQ
дов. а не спе:циаль:ных i1Мl;$ОВaшIЪrx проtpамм обработки собыТий.
Clasg Pl-ОgХillТ1
{
st1:\tiC' V"o.id t1a,in (str :ing 1] args)
I
ConS'ole . W.r i teLirl<o' ('" ." ~ /<т Анонимные методы ,~" ..... " \д") ;
Car сl=л~W Car(('SlugBug", Н)О, 10);
Обратите BJ-IИМани:е:на то. что тип Program уже не опреде-лnет :кoнкpeтlJЫe ета
тические проrpаммы обработки событий. такие :Кан. например. CarAboutToBlo:w ()
а Са:tЕхрl0dэd О . Вм.еето Э'Гого здесь ук,а;JaНЫ безым.яннъte (те, анОtIюmые) мето
ДЫ, Оripe.Деляемы:е "внутри.rтрочно" В тот момещ lШща вызывающая сторона 06"
рабатывает событие, ИCnQJIQЗУЯ СИНТаЕСИС +=.
БазовВ1Й СИНТCffiCЛС анОfЩМНого методасОЬтвстствует слt+(yЮщему представле-
~ пию в псеВДOJtоде.
"
c'la$s Som~t::qll~r
{
sta.t ic v"id M?lin( s tring [j аrg;з)
{
SomeТype t = пе", SфmеТуре () I
t. S'cmeE'I7E'tnt +=
del e,ga'te (веоб;иэа!1'е.llыwApг)?l8R!1щlle'.lfezojl,~i!I))
{ /'" ,операторы ~ I J;
..,...
cl.AboutToBlow += delegate {
Console. Wr i teLine ("Ох! Едем слишком Сыстро! ") ;
);
int aboutToBlowCounter = О;
11 Соs.цание К&IIIИИW.
Car cl = new Car ("SlugBug", 100, 10);
/ / Р.:l:'Ис~&ЦМJII обрабО'1'ЧИJCО:8 событий :8 виде анОНИNНNX кетодов.
c1.AboutToBlow += delegate
{
aboutToBloWCounter++;
Console.WriteLine(" Ox! Едем слvtШК ОМ быс тро!");
};
Console. Wri teLine ("Событvtе AboutToBlow вызывалось (О) раз (а) ."I
aboutToBlowCounter) ;
Console.ReadLine();
Глава В . .ИнrерфеЙсы оБР('!ТНОJi'J lIbJЗОВЗ, делегаты и СQбыт~я 373
в результате в:ыrlOлнения этогО обиовленн:оrо метода Mai n () завершающий оде
ратор COI:!$ole.WriteLine () сооБIi])IТ вам о ТОМ, 'WГ{} соБЫТIil.е АЬоutТQЮQW генери
.ровалось дважды.
cla55 Рrоgr'ёiirп
m.ComputationFinished += ComputationFinishedНandler;
Резюме
в этой главе был рассмотрен ряд подходов, позволяющих реализовать возмож
ность двухстороннего взаимодействия объектов. Сначала было рассмотрено ис
пользование интерфейсов обраmного 6Ь!30Щ которые обеспечивают возможность
для объекта А вызывать объект В с помощью общего интерфеЙса. Этот подход не
является специфическим ДЛЯ . NEТ. а может использоваться в любых языках и на
любых платформах. допускающих программирование на основе интерфейсов.
ь
Глава В. Интерфейсы обраТНQГQ ВЫ:ШВ(1, делеГЗП,1 и события 375
Затем бьmо pa:c:cmotpel-iО Ю1юч.евое слово (:::#dele.gate. которое используется
.Д1IЯ н~np,ямоtо построения классов. D,pomtBOДНЫX От Sys,t em.Mul'ti.c8.$tDeleg,a·te.
Как ВЫЯЦIWIDСЪ. делегат цредставлЯe:F собой об'bl:I-а:. :храняЩИй CIIМCO!{ методов. Д{J
c~ для вы3ва• . При этом Вызовы. jldт'УТ быть ,c.'ИнJCpФ1-ПIblМИ (O.Im RЪЩОЛFШЮТСЯ
с nOМQЩ~ 1\reТoдa lrivoke ( ) ) и.лtt асищронщ.rми (они выttоЛllЯlOТCJlС ПОМОЩЬJQ ме
ТОДОВ 'Веgi nIЛ.VОkе О R Елd111v(\)}~е О). АсищроннанприродаnmОБ депегата . NEТ
будет р'сссмотрев:а позже.
Ключе:вое слово С# еvепt ОрИ использовании сnшом делеl'ата позволяет ynро
entтъ ароцесс отправки еообщеI-ШЙ событий "ВЫЗ'ы:&aIOщим объектам. к.ак пщraэы
вает ГlЩерируe:м::IO::Й CII....kOA. мод~J1ьсоБыщйй .NEТ С:ВОД'ИТ СИ'l)'aциIO 1> CКPЪJТЫMBЫ
завам 1'WIов.8узtero. Dеlеgаtе/S1stеm.МultiсаstDеlеgзtе . В ЭТОЙ СВn;\lИ кдючевое
СЛОВО С# event оказы:вается :необязателъным и просто ЗЕОНОМИТ' время при щборе
текста npограммы.
\
\,;Q'nS01i:! ' W.ri te,Li 'le ("Haм~p ма:шины::' \О' r ", i} 1
СGП'$эlе' , Writ.,.,Line ("Наз:!tilние: IO}" , ~r!.(;',t (i j . l"€.tN<:<П1е,) ;
J:QnSO lt! • W:ti teI,.ln,e ( "Мal'l Cl!1!i1a.m и;ая C ~.'.Jp=''!''&.: (О Р ,
c ~r I,ot [ i) ,еuп sр<;;«,~J.:) ,-
СопsGilе.Wri.tеLl!)$'() :
Перегрузка операций
в С#. кю< и в любом другом языке программирования. есть свой ограниченный
набор лексем. используемых для Вl,шолнения базо:еых операций со встроенными
типами. Так. вы знаете. что операция + применима к двум целым числам и в ре
зультате дает их сумму.
Снова заметим, что это не новость, но вы, наверное, заметили и то, что одна
и та же операция + может применяться R большинству :естроенных типов данных
С#. Рассмотрите. например, следУЮЩИЙ фрагмент программного кода.
/I ОпераЦИR + со строками.
string з1 "He11o";
string э2 = " world!";
3tring з3 = 81 + 82; 11 з3 теперь равно "Hello world!"
L
rлава ~. сп'ециальныe приемы nЩ:т.роен,ия типов 383
1/ переropyжеииаи операции +
public static Point operator + (Point pl, Point р2)
( return new Po int(pl.x t р2.х, рl.у + р2.у);
11 переrop}'Jltеннаи операции
-
p~blic static Point operator - (Point p l , Poi nt р2)
( rеturп new Point(pl.x - р2.х, рl.у - р2.у); f
Точно так же
11
р3
рЗ
= pl - р2;
pl -
= Роiпt.операции-
р2 отображается в следующее.
(pl, р2)
I
Операции += И -+
Если вы изучаете С#. уже имея опыт использования С++ , то можете обратить
внимание на отсутствие возможности перегрузки операторных сокращений, вклю
чающих операцию присваивания (+=, -= И т.д.). Не волнуйтесь, в С# операторные
сокращения с присваиванием моделируются автоматически, если тип предполага·
1/ Автоиаnlчесхаи переropузх& -=
Point ptFour = new Point(O, 500);
Console.WriteLine("ptFour = 101", ptFour);
Console.WriteLine("ptFour -= ptThree: (О}", ptFour -= ptThree);
return' ~аlзе;
)
386 Часть 11. Язык nрограммирования С#
Внутреннее представление
перегруженнbIX операций
ПодОбно любому элемеНТу прох:раммы СИ. переуоружевные операции представ
.лйlOТёл Cnециа.льными элемен-mми CИИ!raНсиса CIL. Откройте. вanрш.rep, 1rollOIOнo
ВО!IНЫЙ блок ОvеrlGаdе:dОрз. ехе с помощью ildasm . еХе. ка1( показано на рис. 9.1.
переI'pyЖeННЪfе операЦИИ внутри блоl".а пре;цстaвJI8ЮТСЯ с:крьrrыми методами (Э1'О,
ilaпpНМ6р. ор_ Add'itiQn О. Ьр _ Subt:;act:ion (), ор_ Equality О и т..I1.).
Теперь. если рас.смотрмь CIL--tnlС:ТрYJЩИИ длg метода ор ~ Addition. 'Го Bl)I ()б
ИВр}!ЖИ'l'e. ЧТО csc. ехе добавл.вет в метод ltiIюч:евое С'ЛОВО specialname .
. ntethod publi~ bid,ebysig epecialname 1/tatia
'valuetype Оvеrl0аdеdОрs.РGiлt
ар Addition (valuetype ОvеrlоаdеdsОрэ ..PDint р1 ,
v$.luetype Ov!'!r loadedOps. Point р2) с11 IТIaлаged
}
388 Часть 11. Язык программирования С#
'" ор Multiply()
I ор Division ()
ор Equality()
> ор GreaterThan ()
< ор LеssТhал ()
!= ор Iлеquаlitу()
>= ор GreaterThanOrEqual ()
<= ор LessThanOrEqual ()
ор SuЬtrасtiоnАsэigпmепt()
+= ор АdditiопАsэignmеnt (J
Глава 9, СпеЦИaJIЬJIIЫ& 11риеМbI rтОСТРQВfIИ~ ТИПОВ 389
Использование перегруженных
операций в ЯЗblках, не nОАЦерж:ивающих
перегрузку опер'аций
ПоНИМание 1"01'0, как перe:rpужен:ные щ:rеpaщm предс1.'авлены в программном
ходе CIL инте.ресно не TOJIЬRO с академи:чес.коЙ Т~ОЧКИ зрении. Чтобы осоа.вать
практИчесrcyю UOJIЪЗY этих зиaщm. вспомните о ТОМ,, что ВОЗМОЖНОСТЬ перегрузКй
операций I10,!Щерж:ивается ' ~ всеми язьшами, предназначенными )VJ,Я .NEI'. RaIc,
нanpим:ер. добавить па.ру типов Poi nt в програм:му, соадавнуюna я.зblJUt. не под
держивающем перегрузку операщШ?
Одним из Подходов 'Являетсн создание "нормальных" oт1cpыты членов. Ю>Торые
будут peIiIaТЬ ту же задачу. что и пере1''Руженнъre опера.1:!;йи. Например. :можно до
бавИТ:Ь в point методы Add (~ и Subt ract () • которые будУТ ВЫПDJIНЯТЪрабо'I'y. со
ответствующую операциям +' :и -.
11 ЭХCnО8J!ЩИJ1, с8ll&Вwиtm пtiреrp~ оп.раЦиЙ
11 с I1OJIoЩWO проC'1'lolX .8Иоа-фУJUЩИЙ.
poolic stп)'с't PQint
{
.i ....
1
--
390 Часть 11. Язык программирования С#
Dim р2 As Point
р2.х = 9
р2.у = 9ВЗ
Замечание. Текущая версия VB . NEТ (Visual Basic .NEТ 2005) перегрузку операций помержива
ет. Однако для других (многочисленных) управЛRемых языков, не поддерживающих перегруэку
операций. знание ·специапьных имен" соответствующих методов CIL может оказаться очень
полезным.
Заключительные замечания
о перегрузке операций
Вы могли убедиться в том. что С# обеспечивает возможность построения типов,
по-своему отвечающих на встроенные всем известные операции. Перед тем как пе
рейти к непосредственной модификации классов для поддержки такого поведения.
вы должны убедиться в том, что для операций. которым вы хотите назначить пере
грузку. такая перегрузка имеет смысл.
1,
1
L
1 Глз&а 9. Специальные прием~ rtЩТРОВtlия типов 391
Преобразования чисел
в случае ВстроЩШЫХЧИСЛ:ОВ"ЫХ ТИПОВ (:sbyte.. int. f10at и 11Д.) явное npeoбразо-
8(l1iUe требуетСЯ тоща. Н.огда вы nы:таетесь.сохранить большее значение в :меньшем
ко~ЙJfере.. ПОСКQJlЬRY при ЭТОМ .ьюжет ПРОИСХОДИТЪ потеря данных, ПQ сути. ·это
способ сказать Щ>мnилятgру приМерно следУЮЩее: аНе бесПOJЮЙCJ:I. 11 знаю, "что де
лаю!~ С дpyrой СТQРQИЫ, неявное npеобраэован.tю происходит автомат~еciШ, :ког
да вы .пытаетесь раэместить в тИпе-адресате тип :меныDиx pщiМеров, в результате
чеГо noтери да.:нных 1ю праисходит.
сlаsз 1?rogram
!
static void Main ()
[
11 B8JDllloe пре;обрааоа&.RU8 Jit!I проиQОрс)roo • б..,оlJlolil_
Вазе wз-Ваs€:Туре:
тyBa~eType = 11е}; De-rived О;
Создание пользовательских
подпрограмм преобразования
в С# есть два ключевых слова. explicit и implicit, предназначенные
для управления тем. как типы должны отвечать на попытки преобразования.
Предположим. что у нас есть следующие определения структур.
L
['пава 9. специaJIьfiыe приемы fIIDстроеНИII ТИПОВ 39Э
Обратите внимание на то. что на этот раз ДЛЯ типа F.ec t angle опредеЛ1J;eт<:Jl
Операция явного преобразования. как и при переГРУ3I~е. встрое1ЩЫХ оп~раций. в
С# для ш)Дпр6грамм прео5рааовани.я иопользуется юnaчевае CJ.IOIЮ opera;tor (в 00-
вокynности С .нmОч:евым словом ехрl ici t .или irnpli c::it) :и этц РОДПРЩР8,~ ДОЛЖ
ны определяТЬСЯ. КВR статические. Входным шtраметром nВляется объe:кr. у.отоpый
вы хотите npeoбрззовать. а возврatЦaемо.е 3Jiaчение - это об'1:Je1a: В который поC1J"
пающий объект ПРевращается.
,
private static \fold D r-аNSquаrе (Sq.uaf8 sч)
вч. Draw () :
--
394 Часть 11. Язык программирования С#
11 Преобразование
Rectanq18 в Square jqmr ВI:IЗО• • иешода.
DrawSquare«Square)rect);
l
Глаза 9. Опециальные приемы построения типов 395
создать QIJ~рi:щmO :ЯВНnrО преобрааова.ниа для дaщroго nmа, совеем не следует, что
вы обя~ ~TO делать. как правило, этоо" подход оказывается паиболее полезным
ТQща, 1(Orдa соэда1ОТen тИпы структуры .NEТ. ПОСIЮльку тахи.е типы не мoryт ис
ПОЛЬЗОВаТЬ иерархии М3.C€ИЧесного наследования (Дo1Ul КOTQPЫX соответствующие
преобрцовamm реализуютс:я автоматичеСlШj.
Определение под.про,грамм
неявного прео6разования
до мого момента мы с вам;и создц.вали пользовательские операции' явного цре
образования. НО что МQЖНО СШJЗЦть О следующем l-I.eЯВНOм:преобразозании?
l
ГJlава9, Специальные приемы ПОI.>1роеl~ИЯ Т}1ПО9 397
;:
_I"JI~
.i
I!II QP_1rtP~ :'I'~t:Jet~e ~pnvet"',OnS.5~nt13z):
,~~tdnI
.~~'--------'-'----~------------~~
~ . ,,
стимоro). Чтобы Мидти в HOry" С CLR. обе эти возможности буl1YТ обозначаться. :как
"переПOJlliение". (и переполнение. и потеря значимости DpJШоДЯт к созданию ТШIа
System.OverflowException. ТИпа System.UnderflowException в библиотеках ба
зовых классов нет.)
1J1rя npимера предположим. что мы создали два экземпляра типа System.Byte
(тип byte в С#). присвоив им эначеl-IИЯ. не превышающие максимального (255).
При сложении значений этих типов (с условием преобразования результата в тип
byte) хотелось бы предполагать. что результат будет точной суммой соответству
ЮIЦИX членов.
namespace CheckedUnchecked
{
c1ass Program
{
static void Main(string[] args)
{
11 Пеpenonвевие дmr Sуstеш.Вуtе.
Console.WrlteLine("MaKc. значение для byte равно {О}.",
byte.MaxVa1ue) ;
Console . Wri teLine ("Мин. значение для byte равно {О}.",
byte. MlnVa1ue) ;
byte bl = 100;
byte ь2 = 250;
byte эит = (byte) (ь! + Ь2);
11 Значением ВuDI. ДОJDlalО бlot'l'Ъ 350, но • ..
Conso1e.WriteLine("sum = {О)", sum);
Conso1e.ReadLine{);
Glli~S l'rogr=
t
static: voi!i ~in(st.Lingl] args)
I
11 D.epeDQmlIЦJИ& ,щzlll Sy8 tеш. Вyte .
Сощ:юl е. Wri tеLiш~ ( "Ma'l(C. 3}iачение для i:;>yte равнС) ! О •. " ,
byt€.Maxvalue):
byte Ы = 100;
byte 1>2 = 2'SO;
try
t
byte suro = cbecKвd! r.h>yte) (Ь1 .j.; Ь2 J)
Cons,ole.WrJ:te;Lir" e ,! "SU!D = {О) ", sum);
J
c ai cb (Ova dlowEx'.c ,e p:t i 'o:(l е-)
{ СОnSОlе.W:ritеLir:JE'!{е,Меэsаgе);
J
ну
I
Checkeci
I
byte зum = (byte) (Ы -1- 1;12') ;
Con~oJ:e. Wri teL,i ,r,e (" БШ'!\ = '! о J ", :rum);
j
c'a tch (ОV'~rflоwЕхсерtiо.п е)
{
Consoie. Wr.i teLine {е .. Мезsаgе., ,
}
Ясно, что эта установка оказывается очень полезной при отладке. После того
t<aК все связанные с переполнением исключения будут из программного кода уда
лены, флаг /checked для последующей компоновки можно отключить.
checked. и вы можете указать для него один оператор или блок операторов, на
пример :
Оп_раЦИII или
Описание
19IJQЧ81О8 ·cnoвo
~;::! ~=, <, >, В l:IеБВЗопамом KO~J'eI(Cre 1( tипам указателR могут ЛРИМ8IiRТbСЯ оflВрации
<=, .. > сраВНaI01яи проеерки на ТО)IЩественмос-ть
I =~
! =-___,
ВtiId 1
1 W~LМ:
~W~:
1I 11
~~-----------~
-J
L I_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
i
Рис. 9.4. Разрешение небезопасного программного кода Visual Studio 2005
$omeQnsafeCooe () ;
404 Часть 11. Язык программирования С#
ипэаЕе
int mylnt;
11 Оnpeдеnени. ухазате.JUI типа int
11 и nPИСВ&И8ание ему адреса myIn t.
int* ptrToMylnt ~ &mylnt;
struct Point
(
public int х;
public int у;
public override string ToString()
{ return string.Format("((OI, (11)", х, у); )
Point point;
Point* р = &point;
р->х = 100;
р->у = 200;
Сопsоlе.WritеLiпе(р->ТоStriпg(» ;
}
11 ДОС'l'УIJ IC членам через раЗJolИеНО8Jo18ание yJC&за'2!e.nеЙ.
unsafe
Point роiпt;
Point* р = &роiпt:
(*р).х = 100;
(*р) . у = 200;
Сопsоlе.WritеLiпе( (*р) .ToString(»;
uпsаfе
p"o.Jb1ic int х:
p~.blic int У;
publio o:verride э ·tring TpStribg: ()
{ returD эtring.Fс·rm.;it(" (\О}, !1n", х, у); }
{
11 ПерекениёUI int* испom.зуеТСII зД'есь.
}
11 Теперь pt не зафИICСИРО8аиа и lIо_ет б»т1o убрана
11 сБОРЩИКОII мусора.
Console.WriteLine ("Значение Роiпt: {О}", pt);
unsafe
Поскольку sizeof может оценить число байтов ДЛЯ любого элемента, произво
дного от System.ValueType, можно получать размеры пользовательских структур.
struct MyValueType
{
public short э;
public int i;
public 10ng 1;
unsafe
{
Console. Wri teLine ("Длина
short равна (О}.", sizeof (short) ) ;
Сопsо1е.WritеLiпе("Длина int равна (О}.", Siz8of(int));
Conso1e. Wri teLine ("Длина long равна (О}.". sizeof (long) ) ;
Сопsо1е.WritеLiле("Длина MyValueType равна (о}.",
sizeof(MyVa1ueType));
Директивы препроцессора С#
Подобцо многим дрyrим яаli!ltaМ йз семейства С. 11 С# IЩЦдер~щотся Ра3ЛИЧ.
ные сим:вoлы. по:mол.monще влиять на процесс комnищщии. Перед рассмотрением
директив препроцеесора С# оогласуем соответствующую терМИНОJ,lЩ'JDO. ТерМИН
·директива прenроцессора С#" не ВI1олне точен. Фавтически этот тepмw- ИСПQJIЬ
зуeтcJ'J тo.цыto J1)IЯ согласованности с ЛЗЫI!Э.МИ npограммиравакия: С. и С-н-. ~ С.#
нет CYJДелЬного щага препроцессара. ДИреltТИВЫ преnpо.цессора :в С# Яв.wnG'N~ со
crcuщDЙ частью npоц~сеа лексического ана.ilяаа ltОМlIИJIЯТОРа.
Так или ~ИБаче. СИНТЮ<СИС диреRТИВ препро:qесСора С# очень .похож 'На сцнтак
сие сортветс:myJOЩИХ диреlt1'ИВ OCTaJIhНЫX члеltов семейства С в ТОМ,· ЧТР эm Д1'I
ре'R:ТИВЫ всегда имеют префlWс, обозначенный знаНОМ «диез" (#). -в таб.л.9.4 ори
сан,Ы некоторые из наибоЛ!~е часто используемых диреН<rив (подробности можно
Щt.Й1'И в документации _NEТ Framework 2.0 ЭОК).
Таблица 9.4. ТИПИllные директивЫ nреПРО4ессора С#
Директивы
1Н Е, #eJ.if. #e l se~ 14спол6зуютс:я ДЛЯ условного ПРОilусkЗ. разделов и'сходноrp кода {НЗ
.ffendif 'OCffOBe указанных СUМIЮЛО8 компиляции}
cla's~ Car
(
priv ate st rlng pe tName;
priv:ate ifJ t Ctlr.r gp i
#reqion Соns truc.t :;ors
рмН 'с Паr ()
{ .. - }
риыic C<J,r Ca r (l.n,: c-u:t rSр , s t :ring petlЫame )
( ... .1
#enliregion
'#:r:8gion Рrореrti8З
public iц t Sp.eed
i ... }
public' string Name
! . -. J
ftещ:1regiоn
}
41 О ЧаСТЬ 11. Язык программирования С#
l' ,
Условная компиляция
Другой пакет директив npепроцессора (Hf. #elif. #else. #endif) позволяет
выполнить КОМIIИЛ.ЯЦИIO блока программного кода по условию. базируясь на npед
варительно 3эдaнных: символах. Классическим вариантом использования этих ди
ректив ЯВJIяется идентификация блока программного кода. который .компилирует
сл только npи отладке (а не npи окончательной компоновке).
class Program
(
static void Main(string[] args)
I
/ / Эorоor прогрaммJDolЙ ход :ВiШo.JlИR8'1'СIII '1'оn.хо при О'1'nадочной
/ / ХОНПИnIllЦИИ ПРО8Хor&.
Jlif DEBUG
Console. Wri teLine ("Каталог приложения: (О}",
Environment.CurrentDirectory);
Console. Wri teLine ("Блок: (О}",
Environment.MachineName);
Console.WriteLine("OC: (О}",
Environment.OSVersion);
Сопsоlе.WritеLiпе("Версия .NET: {О}",
Environment.Version);
#endif
#define DEBU.G
usi rщ sуэ t:em;
П3Ш6sрасе Preproces18or
1
clagg ProcessМe
'Замечание. Директивы #denne в фаЙле С программным КОДОМ с# должны быт,ь указанbl до всех
остщlbl-lых.
#defipe QЕВ1Щ
#defiR6 MONO BV1LD
llsiHg System;
петеБрасе Preproee'Ssor
I
cla,ss Рт'очrаm
[
stat;lc vQ·ipMa'in (string[J агчв)
{
tif МЩЮ ВЩLD
Console. Wri teLi'&€ ("Ко=rВ:ЦИА ДI1Я Мод",) ~ ") I
#'else
СаП1;юl е, wri teLine ("КОМI1ИЛ$ЩИЛ ДЛЯ l{lСГОЭ,Qft. • ЫЕТ") ;
#endif
J lIUid Events
CardtINI:O~~i"" ~-=~~_~- __ -------.J 11 I
~ Deht1EllUG ~
0DehlR6CE-
г. :: ---'-c--- -~--
. ~
~CpU .~I
.. . .
Рис. 9.6. Определение символа препроцессора для применения в рамках всего проеkТа
Резюме
Целью этой главы является более глубокое изучение возможностей языка про
граммирования С#. IЛава началась с обсуждения ряда достаточно сложных кон
струкций программирования (методов индексатора. перегруженных операций и
пользовательских подпрограмм преобразования). Затем был рассмотрен небольшой
набор не слишком широко известных ключевых слов (таких. как sizeof. checked.
unsafe и т.д.). обсуждение которых естественно ПРИВeJ-IO к рассмотрению вопросов
непосредственной работы с типами указателя. При исследовании типов указателя
было показано, что в подавляющем Болыlшнтвеe приложений С# для использова
ния типов указателя нет никакой необходимости.
ГЛАВА 10
Обобщения
С ЦеЛЬЮ ИЛЛЮСТРЦЦИU этой новой возмощности язы:wa :мы начнем .главу с рас
~отре:иия пространства :имеJ-l SуstеЛl.СоllесtiОnS .. GелеriС. PaCCMoтpe~ приме
ры nOilJДсржJ{И обобщендй:в би5лиQтеRaX базо:въrx кдассов.в ОСТЭд,ьной части этой
rnавщ мы JЮIЩТаемСFI ВblSIСнить, KQR строить СВОИ собствtШные Qбобщеmm. членОВ.
RlIЗссов. C'I'JJY"R!ТYP. интерфейсов, и дeд~aTOB.
Ьох [msсоrli.Ь]sуstem.IntЗ2
callvirt instance iпtЗ2 [mscorlib]
System.Collections.ArrayList: :Add(object)
рор
t
Глава 10. Обобщени!! 415
1
-
420 Часть 11. s:lзык программирования С#
Тип Llst<T>
подобно неОбобщенным классам, обобщенцые· lPlaccpr Явллioтс:я объектами,
размещаемыми» ДИIJзмической памити. ПОЭ'Fо~ дди ~ сЛедует испальзt>вa::rь
neW со всеми йеобходю4blМИ ар.ryментам:и конструктора. Кроме того. вы должны
укзза1'Ь ТИIIЫ:. замещающие naра:ме1'\РЫ. оnpедеШЩJЩlе обобщеFШЫМ типом. ТaIl.
ДЛJI Systero.CollectiQ!1s.. GeneriC:. L± st<Y.> требуется указать одно значение, за
дающее вид элемента, с иоторьrм: будет фymщир}щроватъ Ыв t <Т> . например, что·
бы соз-дать три объеltТВ List<> A1lR хранеJiШ[ Це!Щ1Х .:щсел, 1 объектов Эроr. t эСаг и,
объеКТОВ Регsоп. B~ ДOJDIЩJi[ записать следующеt.
Когда вы создаете тип List<T> и указываете для него SportsCar, это эквива
лентно следующему определенюо типа List<T>.
паmеэрасе System.Co11ections.Generic
{
publiC c1ass List<SportsCar> :
IList<SportsCar>, ICol1ection<SportsCar> , IEnumerable<SportsCar> ,
1List, 1Co11ection, IEnumerable
{
typeof(T»,
т ternp;
temp = а;
а = Ь;
Ь = temp;
параметров. Здесь вы заявляете, что метод Swap () может работать с любыми дву
мя параметрами типа <Т>. просто для информации вы выводите имя типа соот
ветствующего заменителя на консоль с помощью оператора С# typeof(). Теперь
рассмотрите следующий метод Main (), в котором происходит обмен между цело
численными и строковыми типами.
Пропускпараметровтипа
I1ри вызове обобщенньц .методов. подQб~ 5wap<T>. у насесть возМОЖНость не
указъmarrъ параметр типа, lЮ ' Т~iЮ .в 1'ОМ с.лygaе, :коща обобщенный метод требу
ет ygааания аРГУМСlIТОВ, ПОСIiОЛЪКУ 1'Orдa RОМЛWlЯТOР может ~в:ы.вснить" тип этих
аргументов па основе BBOДttмЫX паРa1loiетров. Например., можно neреставитъ два
'J'ИПа: Sуэtе1'!1.Вооlеа:n ТШ;:.
1/ ODIибu. ХОНJ:lXnIlЦИИ!
J/ He'R aa.puc8'J1P08? ТОzjДз. .дomcеи бva .!tапо~f;ЩIo!
DisplayВa_eClass() i
temp = а;
а '" Ь;
Ь = temp;
Обратите внимание на то, что тип MyHelperClass сам по себе не SlВJIЯется обоб
щенным. но определяет два обобщенных метода. Так или иначе, теперь. когда ме
тоды Swap<T> и DisplayBaseClass<T> находятся в контексте нового типа класса.
при вызове их членов придется указать имя типа.
1/ OCSоdщeюadi x~c~yцop.
p ti'bl ic Po.±nt (Т' xVal r ' т yVal)
{
Х РО!'! = хУа .!:
YPeJS = yval;
1/ ОбобщеauЩe C80itC'1'В&.
pfiblj..c 'L' Х
{
.get { r~t\J;Ln .кРов: J
set { к?о:з ;= val~; J
public т )."
!
get { return yPos; }
se't ( уРО8 = vi:I ;Lue; .}
xPos = default(T);
yPos = default(T);
Создание пользовательских
обобщенных колnекций
Итак,. пространство имен Sy5tem.CQ11e'c tions.Generic предлагает множество
ТИПОВ, ПОЗВОЛЯЮЩИХ сщ!даватъ эффективные i«JнтеЙнеры. удовлетворяющие тре
бованиям типовой безопасности. С учетом мноЖ€Cтва .ДОC'JYIIНЫX вариwnvв очеНЬ
вe.пИka веРОЯТIЮСТЬ того, -что в .NEТ2.0 У вас вообще не :воз:ютне:г :неоБХодимщ:ти
в ПОСТроеНИИ' пользователъоких lЩПОВ ноллекции. Тем не менее. чтобы по!tЭ.затъ.
как строится обобщецl'IЫЙ контеЩt~р, Jlшnей следyiOщеи задачей будет соэдание
обобхце~ого К:JJncca Rоллtпщи:и, который мы назовем CarCollect :i.on<T>.
ПодобlЮ созцанному выше необобщенному тиny СатСоЦ.е'сt ion, щ1ш новьш
вариант будет использовать, уже существующий тип КОЛЛeJЩИИ д.'IЯ хранещtя сво
их элеМентов '(В' данном случае это L,i st<». Будет реа.тtи:зова:на. и подцержка дик
лаfаr.еасЬ путем реализацlЩ Qбобщeшroго интерфейса IEnumerable<>. Ьбра'l"ИТt'
внимание на то. тrтo 1 Е n \l'Щ е r д ble < > расttm'ряет неоБОБщенный .w;rrерфеЙt1
IEnumerable. поэтому ~омmrnятор ожи.цаеrr. что вы реализуете две l'tерсЩ'l м:етuда
GеtЕдщnеra.tоr ( ). еот K~ может ВbJ'гЛffДеть соответствующая МQJWфИItaЦmI.
11 IEn\Dll8rable<Т> раCllИp•• ~
IEDUIII8rabl., ПОs'1'ОКУ
11 117880 peamuao. .o.n. об•••pc.r
G8tzn\Dll8ra tor () .
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{ return аrСаrз.GеtЕпumеrаtоr(); }
IEnumerator IEnumerable.GetEnumerator()
{ return arCars.GetEnumerator()j )
Console.ReadLine();
}
1/ OJкиБЖ<L!
/ / Нe.nьз. пpesр8'1'М'п> .шип • Т" • ' Cair' !
public void priotPetr:Iame (ir1t ров.)
{
Con sole,. Wri teLine (( (Car) arCars [роз1) .petName) ;'
для решения именно таких npoблем обобщения .NEТ могут опционально опре
деляться с ограничениями, для чего используется ключевое слово where. В .NEТ 2.0
обобщения могут иметь ограничения. описанные Б табл. 10.2.
Таблица 10.2. Возможные ограничения обобщений ДЛЯ пара метров типа
where Т БазовыйКласс Параметр типа <Т> должен быть проиэводным класса, указан
ного параметром БазовыйКласс
_t
r.naB8 1О , Обобщения' 433
Ес.пи вы. хотите изменить nm CarCollection <:Т> так. Ч'tобы D него МОЖ}IO было
.поместить только ПРОИЭВQдm!Iе от Car. вы можете звписать следующее.
)'
СЛедует также понимать то.. ЧТQ при таком orpаничeнuи метод Swap() уже не
смОжет щ:реставля.ть СТРОRO~ые тиIIы (nOC.1<OJ1bКY они S'IВJIЯЮТся ссылочнЫмИ).
так.
arg.TGUppert)) ;
с учетом формата объекта strTarget метод Str i n g Targ e t() должен теперь по
лучить в качестве параметра одну строку,
Это позволяет посылать любой тип данных целевому объекту делегата . но при
этом не гарантируется типовая безопасность. а кроме того, остаются нерешенными
проблемы создания объ ектных образов . Предположим . например. что мы создали
дв а экземпляра My De l eg ate , которые указывают на один и тот же метод MyTa r get .
Обр атите внимание на про блемы с оздания объектных образов и восстановления
значений, а также на отсутствие гарантий типовой безоп асности.
c l ass Program
(
static void Ма i л t st r iпg[] args)
i~\arg 18 stxinq)
!
эtr-inч 5 = (st:c i rlg) a·rg,
'СопsоЪе ,Wrll t~Line r " а,хв liJ :верхнем реrистре: IQ} н •
э.1'оtJрреr(»);
Резюм'е
ОбоCiщeиnя можно Qбoспавamю считать главным из усо~ершенс:г,вnвШJИЙ. пред
I
ложещпФ( в С#2005. Как вы .могщ! убедитьсп. обобщеwlЫЙ ~лемент ПOЗВQляет
yщuш.ть WзanщmителИ (т.е • .I1ара..четры типа), .которые КЩЩР~ИЭffРУЮТСЯ в ыo:мtнт
создa:н:иJJ типа (или вызова, в случае ~бщеища: методов). llQ сугп. обоl$щemm
дaюrr решеви<: npoблем объеК1'ВЫХ образов :и типовой беэоЩl(;ПОСТИ, yc-тrожкящщИк
разработку пpQтрамм: в среде .NEТ 1, 1.
Чаще нс.его вы будете просто ИСЦО.IJ,ьзрватъ Обобщснцые типы. дредла~аемые
БИБл:иотецами базовых классов .NET• .но МОЖ,ИО С9ЗДав~ть и свои собственfIыe
обобщенные типы. При создании обобщеннь:цс ТИnQВ "Мшщ!О указЗ'FЬ лЮбое чпмо
ограничендji. чтоБыI ПОВЫСИТЬ уровень типовой бе~оIIВСНОСТ1l! П' гарантировать. что
соотве:гс:mующие опера::цид будут ВЩПОЛНSJТЬСН С '"иэвес~ 11е:личинами~.
ЧАСТЬ 111
Программирование
к, омпонов ,Qчных
бл'оков .NEТ
Г'ЛАВА 11
компоновочныIe
блоки .NET
Л fu.rn:e
юбое из прwюжeRИЙ. описаянъп в э-rой Кl:iиrе в предыдуЩИХ десяти rлaвa:x..
. об.ычвым: -'aвтoHoмным' :приложением. вел прorpаммнаи lЮI'ИШl KO'J'O~
роro целином содержалась в ОДНОМ ныnоnняm-юм qmйле (... ехе J. Однако ()Д1lCIP~ из
плавных задач платфо'Р1ИЫ .NEТ является ~Ш020кра:т.н.ое ucnОJl.ЬЗOlЮНue npdгpaм
МЫD20 кода. 1IpИ катером при.11ОЖения могут ИCnОЛЪЗfilвать типы. содержащиеся
в разnичныx ВН6ШНИХ ltOМllОНавочных блоках (называемыхтaшke б.иблиотека..l\lИ.
программного Бода). Цмью этой :rлавы будет lIодробное рассмотрение вопросов
сОзданин.. инсталляции И 1Шliфш:урaциn }юмпоновочfLых блmtQВ .NEт.
Сначала мы рас.смотрим pa.aлиtшя меш,цу {)ДНОМО~JIЫШМИ и мнагомо.цульl-iыми
IЮМnQffiЩОЧНЫМИ бло:к.a.м-n, ата.кже мещrw '~ПРИВатНыМИ" й "общедоступными'" ком·
поноШ>чНымИ бланаМИ. Затем мы ВЫНСl:IИМ.• вак среда въшолнения .NEТ onределя
ет I1араметры размещt)НИg IШМlюlюво-ЧНОго блока. и lIоnытаеl>lСЯ IЮRЯТЬ РQJlЬdЛС
(Glnba1 Аsвешы1y СасЬе - rnобальный. ШШ1 комlIонolючных бло&ов), фaйJIОВ КО1tфи
гурац1!.И пр1:uюжения (файлы 1/ .ссmПgJ, поJIИТИКi;J nyб.JIИIШЦии .кcmшоновочНЫХ б,Jl:О
КОВ п ПРОC'Jpанства имен Sуstеш.СопПgurаtiоп.
Управление версиями
Компоновочным блокам .NEТ назначается состоящий из четырех частей число
вой идентификатор версии, имеющий ВИД <главный номер веpcuu>.<до11l)ЛИшneль-
Глава 11. KOMI10КOIOIIHbl8 бnОkИ .NEТ 445
ющ номер веРCUU>.<fФJlЩР КOМnOНQ8I!iU>.<нo.мep 8Цpuaнma> (еоли вы не укажете
mщo ИДeJЦВф:икатор версии с ПОМОЩЬЮ СВОШТJЩ [AssemblNVersfOnl, Jtом:поко
вочный БJ;IрИ RВТO),ЩТJ.IЧеmm п~лучит иденти.фикаТQР :!'epc~ 0.0.0.0), этот ИДeR
ти:ф~тор в сово,кyIIQоСти С }ЦЮБR~атeJlЬИЬ[М ЭНCNeН.ue,м О~ьРПОгО '1CJIЮЧa позво
l1IIeT Мl'JщКеству верCJ.IЙ ОЮlc.:JI'О 11 тoro ~e ;КОМПОНОВОЧНОГО б:J:юRa сосуществовать на
одной и той ~e :м.a:rшnrе в ПОЛНОЙ raР1l!lОНИ:И. Rомпоновочные' блщщ. обеспечива
ющие иифQР;Мацщо об отхр:ытом КJIIOче, нвзьrвaютСR crrrpot:O u..мeкoвaнны:ми. КaI<
будет пока,зано В ЭТQЙ rnаве пещве. при наличии етрогр ЗaдaJnlОro ltМeюt <1реда CLR
enособва rарантировйть-, ч;го ПО 3ацроСу' ВЫзывaIoщег.а клиента БУА~ загружена
имен~1O та версия КOМIJЩЮВОЧИОrQ ~oц, ~ра:я: требуетсВ".
Самооп"са.ние
КОМПОНОВОЧНБIе ~J:lОКИ считают~ еДИНИЦаМИ е чаСТИЧИЬ1И ·самСХДIИЩЦЦlем, по
CIюлысу В них содерЖИТQR информаци~ о внещних:: ко.шОН{i)ВОЧНЫ:Х: блOl(U. необхо
димых для правИJIЪВЩ'О ФYJlКДИOl;lИpовани,я ЩJМЦО~ОВОЧНОro блока. Тц что если
вameЪiIY ROМJIOHOВO"!nroмy блоку J"реб~SуstеIII.Wi.ndоwз.FQrmэ .dl1 и System.
Drawing .dll, то информация О них бу;Цtt ЗaJЩ$Шl в М41iuфecm ltомnolЮВОЧНОro
блока. Вспомните из главы] . что мmщфест- ЭТQ ~JlOК метаданных. ОlШсывающих
сам хампОНОВО'ЧНЫЙ блок [ИМя,версJЩ, ~форМaцЩI О ввешl'lЩ( компоновочных
блоках 'и :I:A.).
Кроме данных манифеста. коМпоновочный блок Co.цe~ fIofeтa,д3rниы,' оnиoы
вь>щие cтpyIaYpy :каждого содержащerocя типа (имена членов, peaЩlЗyемые и;н
терфеЙсы. базовые В'Лв.ссы. lWиcтpyкroры И :I:A.)' И посхо.льиу ROМДЩЮI!OЧНЫЙ б.лqк
,ц:окумеКТI.fPYё'!:СЯ настолыro "кpa:mlОречиво~ • среда CLR 'НЕ ооpa.щйemcя ~ реестру
системыWin32 дла m.шсifения размeIЦeншJ компоновочного блока (что IiрiUЩИ
:mtaJ1ЬiЮ O'l:7IИЧa.eТСЯ от предшu;aвmeЙCSI ранее МIcrosoft модели npo1'JЩММИровamш
СОМ). из Э1'ой rлзвы вы узнаете. 'iТO среда СLR.йcncшьsyет совершенно новую.сему
получения информации о размещении внешних БИБJпroтек ЩЮrpaiММJlom кода.,
Средства конфигурации
КОМIЮновочвые блОКИ МожНо йнс'I'Э.1lЛ&lpo8a'I'ъ как ·npиватнъте
w
ИЩI 'kaJ( "06-
ще,цоСТymiЫе". Приватвые коМJiОI!ОВОЧНhlе блохи размещаются в том Ж~ вата
лоre (шm. возможно. подкаталоrе). что и ИСПОiЛЬ3уЕщее их IфИЛОЖeвJre-юmеwc;
Общ~дО'cтyпньre комnoнО'вочньre CSлeки. RaIIpO'I'.иВ. явлmoтcн библиотеками. дрсту11-
ными для мнО'rиx прuложений. и т.ахие :КОlimоковочные блоки)1стaнaвmmaI01'CН в
специалЬНЫЙ каталог, имеюtt~IЙ специальное название - zл.oбальftый 1CЭШ1CDМ11О
ItOВОЧНbIX БЛOlWв (оле).
Неэависим.о от вида ШIC'1'a11JUIЦIiИ хомпоновo'чных б:локов. вы можете со~аваn.
для них XМL-фвйлы: конфихурацшI. С ПОМОIЩ>Ю этих файлОВ можнО' ДI!I.ТЪ среде СШ
-укааание" с!) том. где C11e/IYeт исхать коМIIЬНОЙОЧные БЛOЮL.какую версию СООТ
ветствующегО' КОМПОНОВQ'ЧНОro блокs. СЛедУет' aarpyэиrъ щ!я КоНкрenroro 1UIИeИ'J'a,
I< lШКON}' каrrалory на ЛОRaJIЬИОЙ машине. в вашей локальной сети или по RЗJI:ом:у
эцданиому адресу URL в Web CJle,цyeт обратиться. Более подРОБНую информацию о'
XML-фаШах КОНфигурации вы ПОJIyЧйте в Дa.лi>Н.eЙШем при изучении материала
ЭТОЙ rдaвы.
446 Часть 111. ПрограММlotрование компоновочных блоков .NET
• Заголовок WinЭ2
• Заголовок CLR
• СIL-код
• Метаданные типа
Первые два элемента (зaroловки WinЗ2 и CLR) - это блоки данных. которыми
вы можете обычно пренебречъ. так что в отношении этих заголовков здесь пред
лarается только самая общая информация. С учетом этого мы и рассмотрим все
указанные элементы по очереди.
Заголовок WiпЗ2
Заголовок WinЗ2 декларирует. что компоновочный блок может загРуЖаться и
управляться средствами операционных систем семейства Windows. Данные этоro
заголовка также идентифицируют тип приложения (консольное. с графическим
интерфейсом или библиотека программного I<ода *.dll). Чтобы увидеть инфор
мацию заголовка Мп32 комnоновочноI'О блока. откройте компоновочный блок
.NEТ с помощью утилиты dumpbin.exe (в ОlЩе командной строки .NEТ Framework
2.0 SDR) с флагом /headers. На рис. 11.1 показана часть информации заголовка
WinЭ2 для компоновочного блока CarLibrary.dll. который вы построите в этой
главе немного позже.
Заголовок CLR
3агОЛОВО1< CLR - зто блок данных. который должны поддерживать все фай
лы .NEТ (и действительно поддерживают. благодаря компилятору С#), чтобы сре
да CLR имела возможность обрабатывать их. ПО сути. зтот заголовок. определяет
множество флагов. позволяющих среде выполнения выяснить структуру данного
управляемого файла . Например. существуют флаги. позволяющие идентифlЩИJЮ
вать размещение метаданных и ресурсов в файле. выяснить версию среды выпол
нения. для которой создавался компоновочный блок, значеЮJе (необязательного)
OTKPblTOro ключа ИТ.д. Если с dumpbin.exe использовать флаг /clrheader. вы по
лучите внутреннюю информацию заголовка CLR для данного КОМIIоновочноro бло
ка .NEТ. как показано на рис . 11.2.
Заголовок CLR компоновочного блока представляется неупрawшемой структурой
С-типа (IMAGE _ COR20 _ HEADER). определенной в файле С-заголовка corhdr.h.
ГIl'llва 11, КОМnОЩ)1;Iочные 51'10l(И .N~T 447
11 иифopиaцlOl С.UII8aJ1ИJ1.
IМAGE DATA DIRECTORY ResQurces;
IМAGE ОАТА DIRECTORY StrongNameSignature;
Снова обращаем ваше внимание на то. что вам. как разработчику .NEТ-прило
жеНИЙ. не придется иметь дело с информацией заголовков Win32 и CLR (за исклю
чением того случая. когда вы захотите построить новый управляемый компилятор).
Вам достаточно пониматъ, что каащый компоновочный блок .NEТ обязательно со
держит эти данные. используемые средой выполнения .NEТ и операцИОЮiОЙ си
стемой Win32.
Заме-.анне. К Зтйму момеЮ'у, наверное, уже не нужно повторять, Что Mi'I просмотра профам
Мl'IOro кода CIL КОМПОНОSО'I~JOГО б1l0К.ц, метаданны){ Т'ИПОВ или м;аНИ~ОТfJ М'QЖНО иrJПеnb3GВ~П.
ildasffi,ex8. Я. предilолarаю, Что вы будетечвсто испOJtЬЗОВ<lТЬ ildasm.ex€ при изучении
примеров ЭТОй тазы.,
Одномодульный
компоковQЧtfbl1i блок
CarLibrary. dll
Манифест
Метаданные типов
СIL-код
Необязательные ресурсы
СSЬажрСиLib .dl.l
Манифест
(сс.ь!лки на дpyrиe
С8Я3аI'f"'ые файТ1Ы)
МеraдвНJiЫВ' lWЮВ
Метаданные типов
ClL-IФА
CIL-k(jД
tucalCa.tLib . natllOdul.
Метадамные ТИЛ08'
соmралуLоqo.b:mр
WюСооtrоl Console
Lbгaтy Дpp!oca1ion
--=
~ P'~ Ь a""tn;! ~ 10 use f1 o~ appIicatJons
еж 11 car1re
Этот класс имеет ОДИН абстрактный метод TurboBoost (). в котором использует
ся ПОЛЬЗ0вателыжий перечень (EngineState). представляющий текущее состояние
двигателя автомобиля,
us ing System:
namespace CarLibrary
{
// Представляет состояние двиrателя.
public епит EngineState
{ engineAlive, engineDead
/ / Абсwpахтный базовый lUIacc в данной иерархии.
public abstract class Car
{
protected string petNamei
protected short currSpeed;
protected short maxSpeedi
protected ЕлgiпеStаtе egnState = EngineState.engineAlivei
public abstract void TurboBoost();
public Car () { )
public Car (string паше, short тах, short curr)
{
petName = пате: maxSpeed = тах: currSpeed = curr:
r ГllаВ8 11. КОМnОflОSОЧliые БJ101(~ .NEТ 453
publlc зtr.i119 r~tNatne
{
get { retu~n petName: }
$et { ре' tЛате = value; '~
}
Теш;rn=o преДПОJIOЩШ;J. что у Еас есть два npiIМЫX "нас.i1едника.~ ТШ1а Cat. имеца
1wтopых MiniVan (мщmвЭН) и SP01':'tsCa:r [CIiOртивный автомобиль}. каждый из них
ПQДХО~ образом lJер~пр~ет аБСтрактный метод ТurЬоВ<юst () .
ьатеsрас'е CarLibrary
;
public clas·s SpQrtsCar : CdI'
(
pUbJ.ic sports:Car О {
p\1blic SportsCar (st.ring паше, sJ:юrt ~, short С11П')
: ha-se (11aт€-, так, CUYr J i ]
puы1!c Gverl:ide ",oio TurboBoo's t ()
{
~YP;--t~~~._______. __~,__
CIImPanO!nt _ _ , RUnIime Раlh
еж 11 CВnaI
Замечание. Можно сделать так, чтобы пользовательские компоновочные блоки тоже появлялись
в списке диалогового окна Add Reference, если установить их копии в папку С: \Program
Files\Microsoft Visual Studio 8\Common7\IDE\PublicAssemblies, но большого
смысла в зтом нет. На вкладке Recent (Недавние ссылки) предлагается список компоновочных
блоков, на которые вы недавно ссылались.
Анализ манифеста
Перед тем как использовать CarLibrary.dll в приложении-клиенте, давайте
выясним, иэ чего СКОМIIонована библиотека программного кода. Предположив.
что наш проект уже скомпилирован, загрузим CarLib['ary.dll в ildasm.exe
(рис. 11.7).
! Dluэ "/1. KOMnaHaBO'ltlbl~ б:nОI(И ,NEТ 455
.module CarLibrary.dll
Наконец. вы можете заметить. что лексема.assernbly используется для обозна
чения понятного имени компоновочного блока (Car1ibrary). в то время как лексема
.module указывает имя самого модуля (Car1ibrary.dll). Лексема .ver определяет
номер версии. назначенный для компоновочного БЛОRa В соответствии с атрибутом
[AssemblyVersion] из Assemblylnfo.cs. Подробнее об управлении версиями ком
поновочного блока будет говориться в зтой главе позже. а сейчас необходимо заме
тить. что групповой символ *в атрибуте [AssernblyVersion] информирует Vlsual
Studio 2005 о необходимости в процессе компиляции выполнить приращение для
идентификатора версии в отношении номеров компоновки и варианта.
Анализ CIL-КОАа
Напомним. что КОМпоновочный блок не содержит специфических ДЛЯ плат
формы инструкций. а СQдержит независимый от платформы СIL-код. Когда среда
выполнения .NEТ загружает компоновочный блок в память. этот СIL-код I<ОМПИ
лируется (с помоIцыо JIТ-компилятора) в инструкции, понятные для данной плат
формы. Если выполнить двойной щелчок на строке метода TurboBoost() класса
SportsCar. с помощью ildasm.exe откроется новое окно. в котором будут ПОRaза
ныI ClL-инструкци:и .
L
r Глава '11, КОМnО~ОВОЧflые '6110КИ .NET 457
.praperty instahoe ltJt16 C;urr8peed ()
(
.get iпstапс€ int16 СаrLiЬr:а.rу.саr::gеt_Сш;r$рееd()
.set inst &dc:e Vb.!.d CarL:ibraxy .Car : :·set-:Сш: rSр е е d (iаt16)
.} I ! eI1d о! p ;r: op ert y Сау; 1 Curr'Spe e d
G18b~
__ ;...'_ _ _ :0-.funetions
_ _ ___________ ________ ~------- _ ____ _ __________ _
--~
. - - ----------=---------_._--------- -----.. . ------~-
Создание ПРИI10жеНИJl-клиеН'та в С#
БВJiД)1 TOfO.• '11'(1) все IЩIЬ1 'c :arLibra r y 6ЫJЦ1 ~)бъявлены с КJlЮ"Чt:lвЫМ словом
publ i >::; . дрytие. EOMnOI-ЮВОЧnыe блоки C1Jocofurы их исnо:rrЫlOвать. Напомним. что
·вы можете также объявлнть типы С ~е.цОЛЬ.З0Ванием клЮчевого Cl10ва С# il1t.e :rnai
(именно этот режl(М доступа в с# исuо.щ:,3YW'РJ по умолча:в:и:ю, ноrда вы определл
ете тип без указания- public) . В~реНI;I;ие тиды мотут использоваться ТОЛЬRО тем
кампоно:вочным блоlЮl\:i. в котором ОЩ1 .оцределены. Внешние кпиеНТli1 не моryr:ни
вJ'Щеть . ни создавa:rъ внутреnниe :гипы ~ОМЩ)~ОВОЧНЫХ блCOOJВ.
Рис. 11.9. Visual Studlo 2005 копирует приватные комnоно80чныe блоки в каталог клиента
using System;
11 Не забу;ць~е 'ис:по.пъзова~ь' простравс~о имен CarLibrary!
using CarLibrary:
патезрасе CSharpCarClient
{
public class CarClient
(
static void Main(string[] args)
(
11 Создание спортивной кашины.
SportsCar viper = new SportsCar("Viper". 240. 40);
viper.TurboBoost();
11 Соадание JlИНИВэна.
Mini Van mv = new Mini Van ( ) ;
mv.TurboBoost();
Console.ReadLine();
;:..
!-"- D_
----'tjpesi
:.;,_.~.~_ _ _ _ ~,i"
~ --=-
.-..-.,- - -- ._ ~. _ __ ._ __-~~ ___
tij ...... с,.
iiii@the'~
I
'* '.........
11 'iI5WIJ#'
Jjj''IIsuaI'c++
.'~
.
WlrldOws
~,.,. g;J
C:lbSh!br...-у
.]ау.'
>мndo"",
i3.
·Wtbc..,,~
11
. ~ OIt1@ ~'IJIII'S ~ C""trOl ubr!Or)' Lluy
.ф]
!
I
I~
\'Jhjo""5
' Y~
~r I'rt>ject
~
gQ..~ .;er
ijj.
'..,
~tPC Podoe!PC
ii
~ 2Oi:Jз "'•.. :2OOJQ...
.r
11
_toc
jS]
Pod;etK
l~jJ: ~
1; PO<I<I!tPC Scм tpllOl'!!. ~~
' . .__ rooзd.._
----'J.~ :100 ;1 r;;a,t - 2O~ COns :.. ~Eт ... ЮОЗ}W•• •
~il
No";t'ar~;~~~, ~- ~==~=
.~ .. \"'~ ~-
..
~ ~ ~-='-=-=--=~--=I,
~, 1c;'tI~ _ _ _ R!1 '!-tt---..-.--"
~J"OON~~'" 1'~~""'ы!'ц J О QmI' g._, fD: ~
DAдdID~Canir8~ . . . . . .
( ок I( с.о4
Как и в С#. в Vlsual Basic , NEТ требуется указать ' С:ПИСQR ~cex цростр~'I.lrств
ямеи. ксполъзуеМ»IX в текущем файле. Но в Visua1 Bask .N~ГдJlЯ этС!IV цр~длата
ется использовать КЛIO"lевое СдОво I.щрогts, а не юrючевое слово lJ s in,g, как в С#.
С учe'roМ этого добавЬТе след,y1QЩИЙ оператор lmport;s 11 фай:т! ЦРQГРаммн:ого пода
Modulel.vh.
Imports ~~rLibrary
End S'tЩ
tnd Modu l e
460 Часть 111. Программирование компоновочных блоков .NEТ
Так или иначе, чтобы использовать типы MiniVan и SportsCa.r в рамках син·
таксиса Visual ВаЮс .NEт, измените метод Main () так, как предлагается ниже.
ЗиЬ Main ()
Console.WriteLine(~***** Забавы с Visual Basic .NET ****-")
Dim myMiniVan As New MiniVan()
myMiniVan.TurboBoost()
Dim mySportsCar As New SportsCar()
mySportsCar.TurboBoQst()
Console.ReadLine()
End ЗиЬ
Imports CarLibrary
, Э'1'О'1' VВ-'1'ИП RВJIJI8'1'CJl произво,цнwм С'-тиnа SportsCar.
Public Class PerformanceCar
Inherits SportsCar
Public Overrides Sub TurboBoost()
Console.WriteLine ("От нуля до 100 за какие-то 4,8 секунды ... ")
End ЗиЬ
End Class
Глава 11, KOMn0!10BIJ4Hыe блокИ .NET 461
Чтобы проверить работу НОIЮГО типа -класса" обно.ви:rе метод Mai n (1 МОдУЛя
так.
, Нас.пе;цуемо& сзоttОI]iВО.
dreamCar •.?etName = "Над k"
t:1.re·a mCar . Тшr.Ь0Вооst ()
СЬп.g.jlе. Rе.а.ШЙп€' ()
Err,j$ub
Обратите B~!= пата, что объект ·dreamC.ar способен Bы3ьtвaть лю.бые от
крытые члепы (н:ац:римf'Р. свойство JЭеtNсаше) по цепочке 'НаслеДОn;;iНИ:Ц,аесмcrrpл
ua 1'0. что базовьЩ клас~ определен I-la сОвершенно другом языке и ВДРУ1'ойбибли
отеке прогрэ;ммното КQда.
name.zp,ace JИrVе.:"iсlесs
!
462 Часть 111. Программирование компоновочных блоков .NET
ь
]
Гмвв11, КОМГJOIiОВОЧliые б-JJОКИ .NEТ 463
.assembly ext:ern mscoriib
(
.рuЫiсkеУtоип = (В7 7А SC 56 19 34 ЕО 89 )
· ver 2; О : О : О
}
.module пiо. пеtпюdul.е
• a,ssemblyexte;rh rrlscorlib
1
.рubliсkеуiшkеп =. (В7 /Л 5С 51:! 1934 E1'J 89 )
· veI 2.: О : О; о
Imports AirVehicles
Module Modulel
ВиЬ Main ()
Dim h As New AirVehicles.Helicopter()
h. TakeOff ()
Console.ReadLine()
End ВиЬ
End Module
. аsзетЫу CarLibrary
{
.ver 1:0:1);54:30104
Процесс ЗОНДИРОВ3НИJI
Среда вьm01IНemiЯ.NEТ ВЫJJсняiп место размещения приватного komnohoboq--
ноro блока с помоЩЬю технологиИ эондuрОвания.. 1I10тары.е на самоМ д.еле оказыва
ют.ся намного менее агреосивными. чемХВЖетсв:из НаэвэЮtя. Зоцдщювание пр.ед
('та:вляет Саба'Й процесс o:rображен:ив зanpосаввешвего компоновочного блоха :в
соответствующее :место раз:мещенJW запрошенного двоИчного файла. Запрос на
эarpyзку RОМn()НQВОЧRОГО блока мажет бшть либо Н€.яsнbVI(, лйбо ЯВf(blМ.. НеЯВfIЫЙ
запрос :выполняется тогда. когда среда СIЯ исполъзует манифест для выяснения
места расположения 'К(}мnонавочвога блока. ОI1ределенноrо с помощью. лексемы
.assem!t:>ly extern.
466 Часть 111. Программирование компоновочных блоков . NEТ
PI.JC. 11. , И. Теперь 'C~I-r:b i b-rar.r. dll рз3Ме!.Ц3етс,1I' .IHWAI<8.Тa:JtQгe }})"i.,iЪ!" .:1.1," Щ
Замечание. Атрибут pr iva tePa th нельзя использовать для указаflИЯ I~И абсолютного (С: \
Палка \Подпапка), ни относительного ( •• \ \ОднаПапка \ \ДругаяПапка) пути! Если вы
хотите указать каталог вне пределов каталога приложения-клиента, вам придется использовать
Чтобы построить файл *'. Qonfig :клиента с ПDМоЩЬW этой ут:t-IJШТЫ, первым
шагQМ должно бъiтъ добавление того приложения.. которО'е будет ~онфигуриро
ваться. дпя этоro 1ЦеЛЧНОМ правой кнопки :мыши ОТRpОЙ're K()нтeXC'I:Нl)e' мета УДJЩ
AppТlcations (IIриложеНИII) R выберите JIYШI.'Т Add Щобавюъ). В пщшившемся диало
ГО1ЮМ Diilie 'Вы можеtne обнаружить придоже1Iйе lIЛЯ lЮНфurypадм при услоlЩИ.
что она вьшолнялосЪ ранее с помЬ'ЩЫО програ:ммы ЛРОВОД1IИК Windows. &ди это не
'IЩ(, ще.лкните на кнопке Other (Другие) 1'1 зайдите в nanкy nPОГJ>Щ>[JI{Pнwиента, ко
торую вы.хоо:и:re конфигурйрова:ть. для даиноro npимера сле.цует ':в:ыlра'Iъ r.rpиложе
ние 'l7bbletCar:Cl ient .ехе. созданное:в этой главе рзнее (поищnте его в rum:кe Birl).
После этого вы ДОЛЖНЫ увидеть НОВЫЙ дочерний УЗeJl. MI\ пощхзавО.Щ1 рис. 11,14.
Если щеЛk1:JYТЪ правой lU-юпкой МЫII1I'i на уме VbNetCarClienl и. QRТивизировать
пункт контекстНого · меню Своистаз', тО внизу шmНИВЦIerося ДШlлогового ок;на !~ !.
увидите :нжстовое поле, где можно ввести '3RaЧf;fШЯ, которые будут ПРИПИСЮJ L.J
атрибуту privatePath. Просто ДЛЯ провеРRИ введще имя подкат;щща Test Dir'
(рис. 11 .15).
470 Часть 111. Программирование компоновочных блоков .NET
Console Root
в·. ,NEТ Frome_k2,O ConflgJr.tion
EI ~ М)' CompUter
," Дs$eтb!y Cache Loсаtюп: C:\Documents апd Settings\Andrew Тnoе!sеп\му
'. с@) Configured AS$OmbllM Documents\My 600ks\C# and the ,[ЧЕТ P!atform 3rd
,- В Remotinli Se1'V1Ce5 Ed\Code\Ch_ll
Ш !iфI Runtime 5e<:urity РоМе)' Code\VbNetCarClient\ VЬNеtСагСliепt\Ып\DеЬШ;J\ VbNetCarClient, еяе
В ~ App!ications
вое'·!
:' .
М'
Assembly Dependencies
This аррliсаtюп сап have its own configured assembIies and
rBmoting s8rvic8s, These settings only affect this опе
.Сф Confio;lured Assemblie. application, Use the tasks below to get started,
В Renю~ПQ ServiCe5
I>OЗfSf1'f JJ dSO<!За
:bDзfsi-1fа~
ЬоЗf5f7F1Jd5!J/IЗa МSJL
.Ьщflif1Щd5lia3;l f'lSlL
=
Рис. 11.• 1'6. I1lОбальный кэш компоноаочны)( БJl10КОS
Чтобы создать строгое имя для компоновочного блока, вашим первым шагом
должно быть генерирование пары юпочей (открытого и секретного) с помощью ути
литы sn.exe .NEf Framework 2 .0 SDK (что мы с вами сделаем чуть позже). Утилита
sn.ex.e генерирует файл. обычно с расширением *.snk (Strollg Name Кеу- ключ
строгого имени). который содержит данные двух разных. но математически свя
занных ключей (зто так называемые "открытый" и "секретный" ключи). Если ком
пилятор С# получит информацию о месте нахождения файла *. sn k, то во время
компиляции значение открытого ключа будет записано в манифест создаваемого
компоновочного блока с помощью лексемы .publickey.
Компилятор С# также сгенерирует хеmиpованный код на основе всего содер
жимого компоновочного блока (ClL-кода. метаданных и т.д.) . вы должны знать из
главы З . что хешupoВQ.Ю-LЫЙ код представляет собой числовое значение, уникальным
образом характеризующее вводимые данные. Так. при изменении любой части ком
поновочного блока (даже одного-единственного символа строкового литерала) .NEТ
комnилятoр генерирует уже другой хешированный код. этот хеmиpованный код ком
бинируется с данными секретного ключа из файла *. s n k для получения цифровой
подписи, встраиваемой в СLR-заголовок компоновочного блона. Процесс создания
строго именованного кОМПоновочного блока схематически показан на рис. 11.17.
След,ует понимать, что данные секретното ключа нигде в манифесте представ
лены не будут - они используется только при создании цифровой подписи содер
жимого компоновочного блока (в совокупности с генерируемым хешированным
кодом). Напомним. , что основной целью применения криптографии на основе ОТ
:крытото и секретного ключей является гарантия тото, что во ·вселенноЙ" .NEТ ни
какая пара компаний. подразделений или ИНДИВИдУУМов не получит одинаковых
идентифи:каторов. Так или иначе, по завершении процесса создания строгого име
ни компоновочный БЛОR можно будет установить в структуру аАС.
Глэsа 11, KOMnoHoBO'IHble блоки ,~EТ 473
MeTaдaftfibIe типов
CIL-JroА
'Рис. 11, 17. В процессе ко,МПИШЩИИ на о,сно,ве QТ!фЫ'ГОГО и C8KpeT1i0rO ключей генерируerо~ циф.
ро,вая t"1OiL\ПИСЬ, KOTopaSj затем встраll1ваеrся е I<ОМПОНОВОЧI-tЫЙ блок '
ЗJlм~.. анме. Строгие ИМ8/i1а d6~спеч~ваlOТ И Щ1РЕЩеленную с.теnень защиты от п'Отенщtат НЫХ, нз·
РУШlIГТелей, пытзющихся модифицировCfrb 'СQдерЖJal'Aое KOMrlOHo,BOLj~JOr(1 блоКiL С учетом Зтаго
в рамках .NEТ CJЦи,аетея целес;ообразfJЫМ сФЗдавать строг!>!'! им~ ДJ1Я каЖДОПJ комп'()новочно
го блока, а I~e только ,цля тех коМпоновочнЫХ блоков, которые предна3~laчены ДЛя установки в
CТPYIC1YJilY GAC
r MANJfI S Т : _ ii !5 1 'Х I
.
ПDlЮВDЧПЫ:Й блок). КЗ1( nO:к.аэано на рис. 11.19.
)(
! , - - -----1 0Si;,tthe~
1:ey~
опцм. Описание
Замечание. При щелчке правой кнопкой мыши на пиктограмме любого компОновочного блока от
крывается контекстное меню, с помощью которого можно открыть страницу свойств компоно
вочного блока или деинсталлировать соответствующую версию (это эквивалентно использова
ния флага /и с утилитой gacutil.exe).
Отложенная подпись
При создании своих собственных компоновочных блоков .NEТ вы можете назна
чать строгие имена. используя свой персональный файл *. snk. Но ваша компания
или подразделение могут отказать вам в доступе к главному файлу *. snk. ВвидУ ис
ключительной важности файла. содержащего открытый и секретный КЛЮЧИ, этому
удивляться не слецует. но это. очевидно. является проблемой. поскольку у вас (как
у разработчика) будет часто возникать необходимость установки компоновочных
блоков в структуру GAC с целью тестирования. Чтобы позволить такое тестирова
ние без предоставления настшuцего файла *. snk. вы можете использовать метод
оmложен.нОЙ n.oдnиcи в случае с файлом CarLibrary.dll в использовании такого
подхода нет никакой необходимости. но мы все же предоставцм краткое описание
соответствующей процедуры.
Процедура отложенной подписи начинается правомочным mщом. имеющим до
cryn к файлу *. snk. с извлечения из зтого файла значения открытого ключа. Для
этого используется ЗП.ехе с опцией -р. позволяющей создать новый файл. содер
ж~ значение открытого ключа.
вп -р myKey.snk testPublicKey.snk
Файл testPublicKey.snk можно предоставить всем разработчикам для созда
ния и проверки cTporo именованных компоновочных блоков. Чтобы сообщить ком
пилятору С# о том, ч.то соответствующий компоновочный блок должен использо
вать процедуру отложенной подписи, разработчик должен установить для атрибута
AssemblyDelaySign значение
true (ИСТШlа). а также указать файл с псевДОКЛЮЧОМ.
как параметр атрибута AssemblyKeyFile. Ниже показаны строки. которые следУет
ввести в файл AssemblyInfo.cs проекта.
[assembly: ASSemblyDelaySign(true)]
[assembly: AssemblYKeyFile(@"C: \ MyKey\testPublicKey.snk)]
Глава 11. KOMnQrlot\o<IHble ·БЛОJ(101 . NEТ 477
Замечание.• Прlll использовании V/sual StudiO 2005 те же атрИбуты МЩКНО создать "ВИЗУШ1blЮ · , ис
ПQПЬЗУЯ 'ВО;3МО~fIOСТИ, предлагаемые на СТJ!ЩНИ'Qе с:sой'ста провкта .
Использование общед,оступных
КОМПОНОВОЧНЫХ блоков
при построеmrn. приложеНИЙ. использующих общедостynные ItOМIЮНtПlочны:е
блоки. е,динствеШIое о.rnич'ие .от случая использОвании прйватного КОМПОRОВОЧНО'
ro б:JIока заключается в том. каи вы ССЫлае1'есь на соответствуюшую fiИб.JlШ)теКу 11
V16дa1 Studio 20.0.5. фaI(тически с точки зрения И'спользуемоl'О ине-трумента IIИКa
кой рааницы нет (ВЫ Псе равно исполъ..~у:ете диалОГОlюе окно Add Refe.rence). Важно
ПОIШТb то.. что это ДИЭJiоговое окно не rюЗООЛUIN вам сослаться на NОМIIОНfJВОчн.ыИ
блок путем просмо·rpа пanжиаssеtnы1у,' ПОПЫТIili сдел8.Тьэто будут бесполезны
ми - возмOJIWОC'tь СОС)1атьси на выделенный lЮМIIОНОВОЧНЫЙ блоu пр~доставдена
це будет (рис. 11.21).
Вместо зтого на вкладке Browse нужно перейти в каталог \B::Ln\Debu:g ()ршu~
~!lы.ыыwгоo npоекта (рис. 11.22).
478 Часть 111. Программировани.е компоновочных блоков .NET
2,0,0.0
I , ОДО
8,0.0,0
I О,2. З600. О
10.2.3600.0
., In . ? , ~ffi!l . n
L1sing CarLibrary;
'i
1
480 Часть 111. Программирование компоновочных блоков ,NET
•
Анализ манифеста SharedCarLibClient
Напомним. что при генерировании строгого имени компоновочного блока в
манифест компоновочного блока записывается значение открытого ключа. Точно
так же. когда клиент ссьmается на строго именованный компоновочный блок. в его
манифест записывается ~конденсированное~ хешированное значение открытого
ключа. обозначенное лексемой .publickey. Если с IIОМОЩЬЮ ildasm.exe открыть
манифест SharedCarL;i.bClient.exe. вы увидите там следующее .
. assemb1y extern CarLibrary
I
.publickeytoken = (21 9Е F3 80 С9 34 8А 38)
.ver 1:0:0:0
Конфигурация общедоступных
компоновочных блоков
Подобно приватным компоновочным блокам. открытый компоновочный блок
можно конфигурировать с помощью файла *. config клиента. Конечно, ввиду того,
что открытые компоновочные блоки находятся по известному адресу (в структуре
GAC) , для них не указывается элемент <privatePath>. как это делается для при
ватных компоновочных блоков (хотя, еCJШ клиент использует как общедоступные.
так и приватные компоновочные блоки. элемент <privatePath> в файле *.config
может присутствовать).
Файлы конфигурации приложения можно использовать в совокупности с обще
доступными компоновочными блоками для того, чтобы дать указание среде CLR
выполнить привязку к другойверсии конкретного компоновочного блока, Т.е. что
бы обойти значение, записанное в манифест клиента. Это может понадобитъся по
целому ряду причин. Например, представьте себе, что вами бъmа выпущена версия
1.0.0.0 компоновочного блока, а через некоторое время вы обнаружили в ней де
фект. Одной из возможностей исправления ситуации может быть перекомпоновка
приложения-клиента, чтобы оно ссъmалось на новую версию компоновочного бло
ка (скажем. 1.1.0.0), свободную от дефекта, и переустановка обновленного клиента
и новой библиотеки на всех соответствующих машинах.
Другим вариантом является поставка новой библиотеки программного кода с
файлом *.config, который автоматически даст среде выполнения инструкцию по
Глава 11. КДМПОFlО;80ЧНl>lе рлеkИ .NET 481
орnвяэ.ке R JlОВОЙ версии (своБQдно;0: от еоответ(;'твующего деф~а). После уствлов
ки новой верcиu библиотеди В струщуру GA.С оригина,льНЫЙ КЛJJe:RТ сможет ра60-
тать без ПQВТQPНОЙ JЮ!vЦnI.,iJ~ и переуста:новки-, а вы не буде'Fе опасат&сн эа свою
рецутаЦИЮ.
Бот еще одна ари:мер. Bbf npеДlIОЖИЛИ нервую версщо (1.0.0.0) КоМnQIJОВОЧНОГО
бllIока. ~ободного от вCJIКИХ дефектов. но I10сле МСС:ЯДS-ДВ)'Х его щ<сuлyатfщии ЕЫ
i добавиди в КQМДОНОВОчtIЬЩ t'lЛО15 новые фymщooНqл::ыlые ~ЩМQЖНости. ПО:i\ВOЛНlO
Также добавьте для типа Car новый открытый метод. который позволит вызы
вающей стороне включить один из имеющихея проигрьmателеЙ.
public abstract cl a ss Ca r
{
publi c Са.!: ()
(
Me ss ageBox. Show( " Ca r 2 .0 .0.0 ");
жете выясди'п) путем ПРОCМD'1'ра манифеста ltПИента с помощыo ildasrn. ехе шrn: в
структуре GA(::.
<ccmfigu:ration;>
-< r:цI1. t irr,1? >
<аsэerobl уВiпdiпg- xmlns="urn: sсheUti1з-m.iсrщ,о ft -(')от: asm. V] ">
<depen den tA$sembly,>
1
484 Часть 111. Программирование компоновочных блоков .NEТ
<assemblYldentity name="CarLibrary"
рubliсКеуТоkеn="191еЬf55б5беОа43"
culture=""/>
<bindingF.edirect oldVersion= "1.0.0.0"
newVersion= "2.0.0.0"/>
</dependentAssembly>
</аssеmblуБiпding>
</runtime>
</configuration>
Снова выполните программу SharedCarLibClient.exe. Вы должны увидеть со
общение о том. что загружена версия 2.0.0.0. Если же для атрибута newVersion
вы укажете значение 1.0.0.0 (шщпростоудалите файл *.confi9). будет загружена
версия 1.0.0.0. поскольку среда CLR найдет в манифесте клиента ytШзание о том,
что необходимо использовать версию 1.0.0.0.
В файле конфигурации клиента может присутствовать несколько элемен
тов <dependentAssembly>. В нашем случае никапой необходимости в этом нет,
но предположим. что манифест SharedCarLibClient.exe ссылается также на
общедоступный компоновочный блок MathLibrary версии 2.5.0.0. Если вы за
хотите перенаправить клиент на использование MathLibrary версии 3.0.0.0
(вдобавок к использованию CarLibrary версии 2.0.0.0). то в этом случае файл
SharedCarLibClient.exe.config должен выглядеть тап.
<configuration>
<runtime>
<аssеmblуБiпding .xmlns="urn:schemas-microsoft-corn:asrn.vl">
<dependentAssembly>
<assemblyldentity name="CarLibrary"
рubliсКеуТоkеП="191еЬf55б5беОа4З"
culture=""/>
<bindingRedirect oldVersion= "1.0.0.0"
newversion= "2.0.0.0"/>
</dependentAssembly>
<dependentAssemb1y>
<assemblyIdentity narne="MathLibrary"
рubliсКеутоkеn="191еЬf55656еОа4З"
culture="" />
<bindingRedirect oldversion= "2.5.0.0"
newVersion= "3.0.0.0"1>
</dependentAssembly>
</аssеmblуБiпdiпg>
</runtime>
</configuration>
<?хтl V'еrэiоn="l.О"?>
<coniiguration>
<ru.n:!:.:lme>
«as'serЦJlyBi ading xmlns=e"arn: sсhеma,s-пtl' стозоft-соm: ' а..sm. vl ";;>
<dе,репdепtАs,эеmЫ у >
<аз эеrnbl у1 denti ty name,=j,j ca;r't ,ibriiry"
ррЫ i cY..€yT,o ke n= "191 еЬ f 55 6 5 5е О а 43" /">
<publish,e .rp,o licy apply"""" yss " 1:-
<bipdingRemil'eCt оld\7еrэiоn;="1. О. О. О" new"'ersi drl=" 2 .,0. о .0" 1>
</dерелdeпtАЭsеmblу>
<) assemblyBindinq>
</ y'u ,n time>
</соnfigur'аti"Оп>
1
486 Часть 111. Программирование компоновочных блоков .NET
Чтобы понять. что на самом деле представляет собой структура GAC, откройте
окно командной строки и перейдите в I{аталог assernbly.
cd c:\windbws\assembly
туре GЛС. Но если при этом среда CLR обнаруживает файл политики публикации.
читаются встроенные в этот файл ХМL-данные и выполняется соответствующее
перенаправление на уровне GAe.
Файлы политики публикации создаются средствами командной строки с помо
щью .NEТ-УТИJШТЫ al.exe (это peДВRTOp связей компоновочного блока). Этот ин
струмент имеет очень много опций. но для построения файла политики публика
ции потребуются указать только следующие данные:
<c.Qnf:i,gurfitiol'J.>
<iruntiroe>
<<1 ss erobl УВindiлg хщlЕS"'"U'rр: SСь'еmiis-miсrоs,оft-сщn: авт. 'Jl ":>
<рublisЬ.r~о'Цс:у apply="no" 1>
<!а.sэеinblуВiпcting>
<./ runtime>
<!СОl1 fi ЧI:j:rаtiол>
Элемент <codeBase>
Файлы :конфиrypации приложениn могут также указать базовый проrрaю.tнblЙ
код. С , помощъю элемента <codeBase> МOЖJ;IО дать инструкцшо среде CLR ИCIЩ'IЪ
зависимые RОА-шо:новочные БЛОЮI в yt<aзанных:меС'1'аХ (mmример. в общеi1 Ce'reJJoj{
naпRе или в ло:ка.iIЬНQМ каталоtе вне хата.1l0га ПРWJРжeниJ{ J(]ЦIeнтa).
Conso~e.ReadLine();
3аМ8Ч8ние. Если размещать КОМПОНОВО'iные блоки в случайных местах на машине, велика вероят
ность того, что у вас, в конце концов, аозникнет необходимость воссоздания реестра системы
(из-за соответствующих проблем DLL). поскольку при перемещении или переименова.нии па
пок, содержащих выполняемые ДВОИ'il-tые файлы приложений, имеющиеся связи будут нару
шаться. В связи с этим используйте <co deEase> с осторожностью.
Предполо:щи!м, " ПО 'у нас есть фаЙл. t.c о п f i g ДЛИ tr.онсолыюго пр~ложения
Арр С ол f igR:e.ad e '[" A~p . в ltOТOPOM 'определяется СТРОIЩ СЩl3И С ба';30Й: дaH;HЬJX и ука
затель на данные t i lТi€s T'o S.ayHe l l o ,
<се)!'!,! 1 чи r а t i cm >
<а.ррS'еt.tinqз>
<a d d k ", у= " а'рр С' 0 f1'St 1: "
iI а 1 ц е = "
"'"' C" ; ~ 1:=1 b L':,al tJ(~з.'t i ul,d= ' s ? " ; :pw'eI= I ' ,; da. ta'b a s <e=Ca. r~ " 1>
<ad,d key= n :citrтe ~ :r o9;;1yHe l 1 o " >,,, 11)f, =" B " 1 ;-
</appSett.ings>
<i с о пf l Ч И ! i:1 tio\'1 ;.
Замечание. В ходе нашего обсуждения ADO.NEТ (см. главу 22) ВЫ узнаете об элементе кон
фигурации < с оп о е с t i о n St r i ngs> и одрутих Тli1IlЭХ пространства имен Sу s t е m.
Configuration. Эти элементы, появившиеся в .NEТ 2.0. предлагают стандаРТНI>!Й метод
обработки строк соединений.
Заnpoo ImtrЮfКlllO'lНOf'Q
блока кnиеtl'ioм ,
ПОМOII
jфм~ноro бnolЦl
в катaлore nриложения I.jDU""~a
и вобycnoмeННЬfХ f-'-
"1..1-
......
-,
nCЩКIПiЛDги
1. [ИмяФаМВJ.dll
2. [имIlФaЙll8..ее
Да:
mporo .мме~IОванНblЙ Успех
Проварk8фаЙ1lOlk!>Нфюурациlt
~ IIЫбор seРСИИ.
прiюрит&ты ПOl'lИТИl!И
(от выошегО /( H~~MYj:
1. q>aйл -.config JII1ИВIIТiI
2. Фaii1 norn.m.1КИ публиki'lЦИИ
З. Фом machlne.con~g
Нет
Резюме
Эта глава посвящена тому. как среда CLR разрешает ссылн:и на внешние ком
поновочные блоки. IЛава начинается с рассмотрения содержимого компоновочно
го блока: заголовка, метаданных. манифеста и СIL-Rода . Затем рассматриваются
создание одномодульных и многомодульных компоновочных блон:ов. а также не
скольких приложений клиента (на разных языках).
Бы смогли убедиться в том. что компоновочные блоки бывают приватными и
общедос'ry"ПНЫМИ. Приватные компоновочные блоки копируются в подкаталог кли
ента. Общедос-ryпные компоновочные блоки устанавливаются в глобальный кэш
компоновочных блоков (GAC). и при этом они должны быть строго именованными .
Наконец. вы узнали о том. что приватные и общедоступные компоновочные блоки
можно конфигурировать, используя ХМL-файлы конфиrypации клиента или, как
альтернативу, файл политики публикации.
ГЛАВА 12
Отображение типов,
динамическое
свсязыIаниеe
и программирование
с помощью атрибутов
.NEТ·
В оставщеЙСfl чаL"ГИ:maвы рассматривается ряд тесно связa.юtbIX ВОПРО.СОIl . ОТ
l-IOС'ЯЩДХGЯ н: возможностям сеРВ:И:СОD отображения. Напр:им:ер. вы узнаете о ТОМ,
lta..f{ .NEТ-клиент .мошет ИCnDЛЬ30ВЗ:Т:Ь динампчесиую ЗМрузъ.'У и д1ll-Iа.>4ПЧеCi(ое· CВЯi-
3Ц1Вa.J:il;Ie ДЛЯ aR'ТИВ"ИЭ3ЦЙИ тишiв . .о наторь!.'" у I{ШJеПТfI нет поJЩОЙ инфор:шщии на
этале l\ОМnИЛЯЦИИ. ВЫ TaJ.Cd«' узнаете. К/;Ш: r ПОМОЩЬЮ СИс.тем:ны:х и 11WIЬз()ВЗтель
скик атрибутов можно· добавить в :компонtшочнщй бло.R _NEf ПОЛЬЗ0ва:гедьсние ме
таданные. ч.тобы :продемонстрировать пе:рсneЕТИВЫ применения зтЮt ($ дерв&щ'
В:ЗТЛЯД I,1злиnще специальных) ВОЗМОjЮ{()стеЙ. глава ззверIllИТС.fI пр:имером постро
ения нес.RОЛЬКИХ ~BCTpHnвae:мыx~ объектов. I{OTOpbre вы сможете дРба.в;ить в рас
.ширяемое приложеНJН:~ WlпdоWsF{:)Frrl.
r
496 Часть 111. Программирование компоновочных блоков. NET
Метаданные типов
Возможность полного описания типов (классов, интерфейсов, CTPYRТYP. переч
ней и делегатов) с помощью метаданных является главной особенностью платфор
мы .NEТ. Многие .NЕТ-технологии, такие как сериализация объектов. удаленное
взаимодействие .NEТ и Web-сервисы XМL, требуют, чтобы среда выполнения имела
возможность выяснить форматы используемых типов. Возможности межЪЯЗЫRово
го взаимодействия, поддержка компилятора и возможности IпtеШSeпsе среды раз
работки тоже зависят от конкретного описания типов.
Важность метаданных очевидна и, возможно. именно поэтому они не являются
новой идеей. предложенной в рамках .NEТ Framework. Технологии Java. CORВA и
СОМ уже использовали аналогичные понятия. Например, для описания типов. со
держащихся в серверах СОМ. используются библиотеки СОМ-типов (по сути, они
представляют собой просто скомпилированный IDL-код). Как и СОМ, библиотеки
программного кода .NET также поддерживают метаданные типов. Конечно, ме
таданные .NEТ синтаксически совершенно не похожи на IDL (lnterface Deftn1tlon
Language - язык описания интерфейсов, используется в СОМ-технологиях для
спецификации интерфейсов объектов СОМ). Напомним. что просматривать мета
данные типов компоновочного блока поэволяет утилита ildasm.exe (см. rлаву 1).
Если вы откроете с помощью ildasm.exe любой компоновочный блок *.dl,l или
* . е хе, созданный вами в процесс е изучения материала этой книги (например,
CarLibrary.dll), и нажмете :комбинацию клавиш <Ctrl+M>. то увидите соответ
ствующие метаданные (рис. 12.1).
Как видите. ildasrn.exe отображает метаданные .NЕТ-тила очень подробно
(двоичный формат оказывается гораздо более компактным). Если бы здесь потре
бовалось привести описание метаданных компоновочного блока CarLibrary.dll
целиком. оно бы заняло несколько страниц. Это бьmо бы лишней тратой вашего
времени (и бумаги тоже). так что давайте рассмотрим метаданные только IUIIOче
вых типов ИЗ компоновочного блока CarLibrary.dll.
Field 12 (~IIIID2)
ТypeDef *1
-------------~----~-------~-------~---~----------~---
F.ield #2
----;;;...-- - -.- -- ---- ---- --- - -.--;.... ...... _----'._- -.:-.---- -..:...~- --"--'--'--'---
Fie}G Ыате: engi.neAlive ~()400()002)
Flagi5: [Plililic:j [Staticj СИtеrаl] IИ"S.Dеfа!Jlt] (u.О[}{1В115б)
DeflH alue: \14)
T
О
СаllСпVТ!tn: 1FIELD]
rield type : Vаllдеtl-ёJSЭ СаrI,iЬrаrу.ЕtJgif1еStщtе
.. .
MeTxaTypDefName используется ДЛЯ вмени типа. МеТJ{З метаданных Extends
используется ДЛЯ указания базового класса .данноrо типа .NET '(В дs.нн(\м случае
это т.и:п Sуstеш.ЕшШl. обозначе:НН.1>rЙ Kai( Typ€Ref). Каждое поле перечня обозначе
но метной "'F'ield #п". ДJ1Я примера здi1iсь представлены только метаданные П()JIЯ
Enginest,,-t..e. eng ineAl i v.e.
TypeDef #3
Method #1
Property #1
Прежде всего, отметьте то, что метаданные класса Car указывают базовый класс
типа и включают различные флаги, использова.Бlпиеся ЕОНСТРУКТОРОМ типа при его
создании (ТaRие ЕаЕ [publicJ, [abstract] и т.п.). Методы (например. ЕОНСТРУЕтОР
класса Сау) описаны с учетом их имени, параметров и возвращаемого значения.
НаЕонец, обратите внимание на то, что свойства представляются внутренними ме
тодами get /set с использованием меТОЕ
Setter/Getter метадro-iнbIХ.NEт. Как
и следует ожидать, производныетипы Car (это SportsCar и MiniVan) описываются
аналогично.
Гмва 12. Отоб:ражение ТИПDВ , динаМИlfеrжое СВЯIJblВЗ-Ю1е . .. 499
Анализ TypeBef
Напомним. "<по Метад.анные ROМnQН"QВОЧllorо t)лоШl ОllИQlJ,ВаЮт не :голыш множе-
С'ФО ввутреJ,IНИX типов (Car" EnglneSt~te И 1:Д.). 1Ю и внешние nmы. на которые CCЫ J
JЩ~СЯ данный lЮМnCllвовочm.IЙ блод. Нanpиъlер. поскwn.нy ~a:z;Libra.ry. dll апреде
~ два neречнп, n описании upисутC1'Rуer блок TypeRef ДItЯ тИПа System .EnlJТn.
тyp8Refll (010оаОО1)
- .... ~----_ . __-:-._-_._ -------------_ .... _-----------------------~
'I'оkе-л: QXiOlO{/O'OOl
Reso1 uti:OnSc;ope: Ох2ЗООО(J"O, 1
TypeRef:N.a,me: SysteJD.EnUIR
МemЬerRef #1
- -----------------_....._----------------- -- ------------~---
AsНlllbly
- --- ------------------~
. --- ----- ---------------~-
Token~Ox20(J00001
йате ~ Ca,r1.i·b rar'i
PuЬHc 1<еу : 00 24: ао 00 04 ВО 0.0 00 11 JI .... д.
A888lllblyR8f 12
Token: Ох23000002
Public Кеу or Token: Ь7 7а 5с 56 19 34 еО 89
Name: System.Windows.Forms
Version: 2.0.3600.0
Major Version: ОхОООООО02
Minor Version: ОхОООООООО
Build Number: ОхОООООе10
Revision Number: ОхОООООООО
Locale: <null>
HashValue Blob:
Flags: [попе] (00000000)
Тип ОnИСl!l'Iие
Тип Описание
Очевидно, что этот ПОдход будет оправдан только в том случае, когда вы име
ете информацию о соответствующем типе (в данном случае это тип Sportscar)
во время компиляциn. При этом становится ясно, что такие инструменты, как
ildasrr.. exe. не MoryT получать информацию о типах путем непосредственно вы
Зова System.Object.GetType (), поскольку ildasm.exe не компилируется вместе с
пользовательскими компоновочными блоками.
[ЛIJ,ва 12. Отоfipажеl1ие n1ПОI\, дина"ичеСJtQе евяэыва~ие.. . 503
СЛедует 1:аюие :шать о ТОМ. 'l'I'O В строке. передаваемой 'МеТОДУ Get Туре ( ) • может
.npш:утствоват.ь знак "rurюc" (+). ИСIIользуемыйдля обозначения вложеJ-tЖ>2Oтuna.
Предположим, ЧТ() мы хотим получить информaщlЮ для перечня (S'руОрtiол s' j •
.БJIOЖeНifоro в Класс JamesBondCar. для этого мы доJ!жны написать следующее.
/I П~ ~ с lШIIQЩ,Jd) qpeof.
Туре t = ~o~(SpDrtsCat):
Отображение методов
Мы модифицируем класс Program. чтобы определить ряд статических методов.
IЩЖДЫй из которых будет иметь один параметр System. Туре и возвращать void.
Начнем с метода ListMethods (). который (как вы можете доraдаться сами) печатает
имена всех методов. определешlЫX указанным на входе ТИПоМ. При ЭТОМ заметим, что
Type.GetMethods () возвращает массив типов System.Reflection.MethodInfo.
// Отображение _ен методо. типа.
public static void ListMethods(Type t)
(
Console.WriteLine("***** Методы *****");
MethodInfo [] mi = t. GetMethods () ;
foreach(MethodInfo m in mi)
Сопsоlе.WritеLiпе("->{О}", m.Name)i
Console.WriteLine("") ;
Реализация Main()
Метод Main () класса Program запрашивает у пользователя абсолютное имя
типа. После получения СТРOItoвых данных они передаются методу Туре .GetType ().
а извлеченный объект System.Type отправляется каждому из вспомогательных
методов. это повторяется до тех пор. пока пользователь не нажмет клавишу <Q>.
чтобы завершить выполнение приложения.
c.atch
while (!userlsDone);
f)Jasa 12. ОТОбражение тиnы3..• динаlAи,4еСI(08 овязывзtlИ'е . " 507
к этому MOMeQ.:IY U}щлошеuие mytype'Jiewe-r . e.)<:~ уже t'OТOВO )VlA Tect'OBoro запу
ска. Запустите это прилощеиие и введите. следующие аБсolIютныe имена (помните
() том .. что rrpи исполъзуемом здесь варианте вьtзова Туре . G.etTyp е (} строки имен
// Получение параметров.
f or ea ch (Раrаmеtеrlлfо p i iл m.GetParameters())
1
paramlnfo t= s trin g.Fo r mat("{ O) { l} " ,
pi .Pa ramet erType, pi.Name);
paraml n Eo += ")";
1/ Отображение основных хара~теристи~ метода.
Сопsоlе.WritеLiпе("->{Оf {l} (2)", retVal, m.Name, paramlnfo);
Весьма увлекательно. не так ли? Ясно, что пространство имен System. Reflection
и Iwacc S у s·t ет. Т У Р е позволяют отображать многие другие характеристики типа. а
не только те. которые в настоящий момент реализованы в MyTyp eViewer. Вы впра
ве надеяться на то. что можно будет исследовать события типа. выяснить., какие
Гnав:а 12. Отображение ТИПОВ , ДИНIШИЧt!ское СВl1зываl1lofе .. . 509
интq>фeйс~ реализоР8НЫ JДlНo. полyчwrъ СПИСОК ОБОБщенных параметров для зз
Д3Нf!}ilY. ч:ленов ицровер~ МJlQжеСТIЮ ДРУIИХ.хар3RТe'pИСТИR.
Но и jI нынеIЩIем СВоем ВИД-е ваш обозреватель объе.Itтов уже :КQе~что умеет.
'DJЯf\Юх1М его огранич:enием. RЩ'lе~mо же. является то, что у вас нет нишпсой воз
МQЖНОL"ТИ отРбража~ ОбъeRJ'Ы . размещенные вне дап:нOJ'о IWМПOНОВОЧНОГО блока
(MyTypeVlewer) щm :вcerд~ дрC':l"}'11lmГО IПsСоrliЬ·.dll. В CВJl3И с этим остается от
RpытымщIJpрс:: ~~ строШ1> приложения. которые могут эarpyжать (и отобра
жать) КОМ:ПОН9вочцые бдОЕИ. о 1С0Т9рых нет информациИ во время .номnиляции?"'
Динамически эаrружаемые
компоновочные блоки
Из преДыдУЩей главы B~ узnали о 'ТОМ' !(аБ Среда CLR :Щ:;rIОJ):ьзуеll ИI:Iформа
цию манифеста RОМШЩQВОЧВОГО блока при 3f.ЩЦ1:fРОВQНИИ КО~ОНОВОЧВЩХ: f)ЩЖОВ
пр внеIIIflИМ ССЦ1Щ(аМ. Все ЭJ'O. конечно. ХОРОIuo, RO во ....щогнх случаях бывает не
dбxQД}ЦI4O Нна лету'" загрузить КО:МЛDНОВОЧ:НI;dЙ б:щ:щ проrраммными средствgми. а
записей о соответствующем RDМПОНОВО~ОМ бдGК~ ~. ~anwфесtt ает. Форма:лъно
зarРУЗJCa' ~неIIЦП{X KOМnOHOB·D~н.ьm блонов ЦО зацросу FIаэьmается дWtClМtlЧeCJCoЙ
эагрузкоt1
В p~цx System. Rеflесt,iОnQлределяетCJ{ Jf,JIащ:. ИМ~ КОТСРОl'О Assembly.
Иcnольау.я:этот тип. можно дщraМ,IiчеClQi затруэ~ любой JtомnоиовоЧНblЙ блок.
а та.юке вынсни.тъ ето СЩЩС1;'Ба. ИСJ;Ющ.зуя ТЩ1 АэsеrпЫу. можно дина:мичеC1tИ за
гружать npиватные и общеДОС'1j'IlRЫ6 КQ~ОНQвочньте МОМ. размещemше в лю
бом месте системы. Класс А,Б- БетЫу предлarает методы (В частности. Load () и
1,oadFrom (»). ПО~ВОJl:яющие проrраммными срещства:ми получать информацию.
ая:8JJ;DIWDJyJQ той. щrгорая ~дерщитcJ;l в файле *. Gon.fig юmента...
,Ддв ЦРИl'<lера испОльзования диnвмичeCRoЙ зarpувки СОЭД8Йreновое КО~OПЫJ'ое
при.п~Ю,Jе с им-енe:t\of Е~tеrnаlА5sеmblуReflес1:.Фl:. Вanrей задаЧёЙ JlВmien:я по
строе;ъше· !оо(етода Main () • запрamивa:ioщего попятное имя RQМn01IОВОЧНОГО бло'Ка
Д1Ш .щп:lаМ}iче(:;к.оЙаатрузки. Ccьmкa. Аsвещblу будет передана вcnомоraтельному
меТ9ДУ Displ ауТуреэ ,() . :который просто напечатает имена всех .классов, интер
фей~в, r;тp)'WIYp. перечней 1iI делегатоВсоответc:myющего компоновочного блока.
f-leo(}1ЩЦИМblЙ программный :код ВЫРJU1ДИТДОВОЛЫlо просто.
using Systemi
1I1sing System.Relfl!?ction;
using SysteI!L.IO; /1 Да. сШре~еа8нkR FileNotFounclExceptlon.
nаmе-эрасе Ex t ethalAsseД1blyR:eflector
(
c.lass. Pro.gram
{
static voi d Diврlау'I' урезlлАЗ1Il . fАsS:еmhlу а sщJ
{
Сопsоl е . Wri teLine- ( "\л" ...", ТИПЫ :КОМ:ПОНО'ВО 'ЧНGГО блока ,Н'" ") ;
:C onsole. Wri teI,irle ("-> {О)", asiIi. Fl1l1Name) j
r
catch
(
С опsоlе . WritеLiпе("Извините, компоновочный блок не найден.");
}
whi l e (!userIsDone);
Отображение Q,бщедоступных
компоновочных блоков
Raя ВЬТ можете ,щогаДЬШа'JЪСЯ, :Мt;ТОД Assembly. Load () является пере:гружеННБIМ.
Один :иа вариантов метода АssащЬ1у.Lоаd CJ ПDзвоМет уканать ЗНН"!еНИе параме
'траои1 t\JJ'"e (для щщanи3ОВЩПIЫХ liомп()новочных блоков). а также номер версии 'и
значение OTy~pЫTOГO .ключ;а (для общедос'lУПНЫК КОМnОНОВОЧFJhEl!: БЛORОВ).
B~cь цабор эл~ментов. идентифицирующих номпаНЬRОЧ:Fiъtй блан, 'Пазътвают'
дш.;rureЙны:м [или опюбражае.NН:iLМ) LUlwн.ем. ПО CBOf."JV!Y формату дисплейное имя
представляет собой CTPORY пар lwеБ М значений, разделенныхзan.ятыми, ноторм
начинается с ПОRЯТНОro имени RD:rvшонmющюго бiJJ{JV.а и продолжается необнза:гепь
ными о:аределени.ями (они могут унааывапюя в любом ПОР.f.IДR'Cl. ВОТ нан выг:щ(ит
соответствующий mаfl..,"Iш-t (В скобках УЕазаНbl необffilатe.JIЫJblf: элементы).
USill g System ;
u si ng Sys t em.Refle c ti o n;
using System .IO;
Con so le. Writ e Line ( " ***** О т о бражени е О бще дос тупных КБ ***** \ п"):
Глава 12.0тобраЖ8ние 'I!ПO-S, динамичео~ое СВЯ3~!lа..~е. ..513
Чуде<:но! К этому моменту нamero Qбсуждени.f,f B1jl ДОЩJUJЫ ДОНЯТЬ, кан U'споль·
зоватъ некоторые базовые элементы из npщ:тр<Щства ~ЩJ $ystem. ~.e П-есti0П для
чтения метадaRНБIX' ROМПОRО:ВЬ'П'iОто' блока во время ВЫДОJUIЩ;.IЩJ. 3дес;ь Я ГОТЩI
npи;з~ть. ЧТО. несмотря на ·фшстор красоты" ПРедщ.ц'аемого ПQд;1ЦJда. вам IЮ РОДУ
своей деят.елъности вряд ли придется строить ПОJ1Ьзовател:ьсКЩI навщ-аторы o~.к
ТОВ. НО не следУет 'забывать о том. чrо сер'Висы отображения ЯIЦl.J1ЮТСiJJ ос:аовой
цe:n:аго ряда друтих. ОЧень широко ИGПОЛЬЗУe1'dЫX. noдXOAOBB ПРОГ~РОЩЩИИ.
включая и дШiaмuчecx:ое связыван:ue.
Дина.мическое связывание
"Уцрощеl'n-ro г.ойоря, дшta.мuчесiOOe' св..чзывnн.ue, и.iШ дWf.йМUЧР..ская' nPUВЯЗЩ
ЗТО подхрд. с ПОМОЩЬЮ которого МОЖНо создавать э~эемпллpьi заданного пша и
~:Ы9:ьtвaTЪ :WX ЧдfЩbl 'fI среде 8ЪЩОЛlleIOШ :в условиях, когда во В'реМЯ КОМlIИЛЯЦИИ о
Класс System.ActiYator
Кпасе Sуstеm.Асtivаtщ:: обеcnе'ЩВает возможностъ реализации процесса дн
намичеCRоij прИВ8ЗКИ в .NEТ. Кроме метОДРВ. унаедедовзщrы:x: 01' System.bbj.ect.
сам класс Act i ',.;;1 tor определяет очень неБОЛЬШ~lvщ(')жество ЧЛЩJОВ. МБGгие ИЗ ко
торых ОТНОСЯТСЯ R CpeдCT.Qaм удалениого взаим:оде'ЙСТВШI .NEТ (ем. гл:аву 18).. для
514 Часть 111, Программирование КОМПОНОВОЧНЫХ блоков ,NEТ
catch(FileNotFoundException е)
(
Console.WriteLine(e.Message) ;
Console.ReadLine() ;
return;
)
Потребители атрибутов
КaR вы можете:цогадатьсs . в комПЛекте с .NEТ Framework 2.0 SDK поставляется
мноЖеСтво)"rlbШт. предпазначeнн:ьtx Д1IЯ работы е ра3.1IИчны:ми атрибутами, Даже
компиmrтар С# (еэс .ехе) зanpогрiiММИpеван lIа проверку определенных атрибутов
.Б процессе RОМiIИJlЯЦИИ. Например. если :компилятор С# обиаруживает атрибут
iСLSСФm:pilаnt)., он азТО1\4атпч:есК!й прОВернет соответствующий мементна совм:е
етимоотъ всех ето конструкций с СLБ. Если же RОМПИJtfJтОР С# обндружИ'l' элемещ
с атрибутом 1Ob$Olete 1. в окне сообщений об ЩI!ибках Visua1 StudJo 2005 ИОЯВИТ
ся CDо.Тilетствующее предупреждение.
Аtpибyr Описание
• MAbllFFSТ
jSe:I;"iali".able,
Obsolete ("Клас('; устарел, ИG riО.льэуй"те другой траяспорт! ") j
рuЬНс сlаЗ5 HQrsel\n,(iВuggy
I
11 ...
tSerializable].
.l Obsole'te ! "YJ!6CC ус'Гдре,р I ;исп~дь:s!ТЙте другоЙт.раисГlОРТ!") ]
puD.J.ic class Hor sеАпdВuggy
{
11 . . .
[SerializableAttribute]
[ObsoleteAttribute ("кдасс устарел, используйте другой транспорт!") ]
public class HorseAndВuggy
{
/ / ...
Это упрощение предлагается самим языком С#, и следует подчеркнуть, ЧТО эту
особенность поддерживают не все языки .NEТ. Так или иначе, к этому моменту на
шего обсуждения вы должны понимать следующие основные особенности, касаю
щиеся атрибутов .NEТ.
• Атрибуты будут бесполезны до тех пор, пока другой агент не отобразит их.
1/ Дщц.ЗО:8а:oмm.CJЩЯ а'l1Щб~.
public s ·e a.led. сlаэs \iet',icleDescriptionAittribute S"Y1;;'Cem.~·f...trib1Jte
{
p-r i Уа ·!:,.е ;>tri ng msgDa'1:a;
publi.c Vebi.cl€Desi:riptionAttribute ('str lng оезсТ iptlon')
j msgData = dе.эсriрtion;}
public ve1'tiCleDsscriptionAttribute CJ { }'
publ.ic. string Des criptior!
r
qet{ retur.n msg9a·!:.a; 1
set { msgDeta = value·; }-
)
IBeria1izable,
Veh!сl_D8.cr.iptlаnЩеsсriрti.оn = "Мой сияюЩий Харлей"))
522 Часть 111. Программирование компоновочных блоков .NEТ
[SerializableAttribute]
[ObsoleteAt tribute (" Класс устарел, используйте другой транспорт!") ,
VehicleDescription ("Старая серая кляча, она уже совсем не та ... ") ]
public class HorseAndBuggy
{
// ...
Соа.Т.~ше~ прив~чкой ДРllJКIiJ) стап, явное УlCЗЗВние флагов применеNИЯ ДЛ!j люБОГQ с:оадавае
м.ого вами пользователЬского аТРlilбута. поскольку не все языки лporР<I.Ммирования , NEТ при
ветЩI;IYЮТ использование атр.iIIбутов, не имеющих квалификационных указанииl
-
524 Часть 111. Программирование компоновочных блоков .NET
11 Тип»
ulonq ве СQглаСуа)ТСJl с CLS.
public class Winnebago
I
public ulonq notCompliant;
l'ii
s
$oIu1ion 'A~"'y' (1 project)
i!I AttJtЬutedC...ut..."..,
Iij
'iJI F'rope1les
~E_ ;
:iiI R~..,.,.ces.гes><
i.:!I ReМOI1Ce<
'i1 Classl.cs
Этот файл является удобным местом для хранения атрибутов, которые должны
применяться на уровне .компоновочноrо блока. В табл. 12.4 приводится список не
которых атрибутов уровня компоновочного блока, о которых вам следует знать.
Атрибут Описание
using Sуstеm.Rеflесtiол;
, }
CO.nsole . ReadLine () :
·1
i
Если вы вlщматеды11о ~адизировIPIИ все примеры этой главы, Т() лисnщг этого
метода Main () долж~}]бъжn. jJ,ЛJllJас (более или менее) поНЯ'I1lhlМ. ЕДИНСТ8еюlblМ
заслуживающим вuиман~ Моментом ~дeeь лвлвется использование метода
Перспективыотображения, статического
и динамического связывания
и пользовательских атрибутов
Даже после множества примеров применения соответствующих подходов вам
может быть не ясно. когда же следует использовать отображение. динамическую
загрузку. динамическое связывание и пользовательские атрибуты в программах.
Строго говоря. эти вопросы (которые увлекательны сами цо себе) можно ОТНеСТи.
скорее. к теоретической стороне программирования (что можно считать как до
стоинством. так и недостатком. в зависимости от точки зрения). Чтобы спроеци
ровать эти вопросы на реальность. нам нужен реальный пример. Представьте себе
на минуту. что вы работаете в команде программистов. созданной Д1Iя разработки
приложения. удовлетворяющего следующему требованию:
Создание CommonSnappabIeТypes.dll
'('Щр~OJ) нamейзадачей ИВJIяется создание комnоиовочнorо MOIta, содержащего
типы. :которые должен ИСDОJIВ8ОВМ'Ь ЕSЖЦЫЙ подкmoчаемый MOд.YJIЬ, чтобы о(\еспе
'чи'гь B03:МO~CТЪ его подкшочении.1t нашему прИЛdжению WJndowsFbrms. Проект
биб;цютеrщ: массов CommonSflappableT~'peB определяет Сjlедующие два типа.
r.amespace СОПТЛIопsпа:рраЫеТуреs
J
puыic interfa'ce IАррF1шсtiопаlitу
{
void Dolt ()1
usi ng System;
u sing CommonSnappableTypes ;
using System.Windows.Forms;
n ame space CShar'pSnapIn
(
[CompanyInfo (Name = .. Intertech Training",
Orl = .. www.intertechtraining.com .. ) ]
public class TheCsharpModule : IAppFunctionality
(
void IAppFun ctionality.Do It()
{
MessageBox. Show ("Вы только ЧТО п о дключили блок ct! .. ) :
ГJlaв!! 12. Отобр;жеНJ.!е типов, ДИН!JМИ4~СlCое связываНие.,. 531
Обратит·е В.}.Jимание Щ!. TQ. ч'то· :здесь используется ЯВная реализация интер
фейса IAp:pFul1ctionality. Это не Обнза.тельно,:но иден в ТОМ. ЧТО еДИНC'rВенной.
частью системы, КDтор",й ПОЩlДобится RеIlOсредотвенное Взаимодействие с этим
типом интерфейса. Я:В,JUlе1'СЯ н:m:ю расширяемое npиложешrе Windows.
Ib»ори'IЪ здесь (юобенно не о чем. Однако обратите Бииr.,m:J-ше }Щ ТО. что СИНТЗК.
сие применепии атрибугов в Vlзuа1 Basfc .NEТ прeдnолa:rает ИСIJрльзование Уl":ЛО
вых «». а не 1:tBaдp8.'rиых ([1) сJ:tOбсж.
Соэдание расширяе·мо,ro приnожения Windows FQrms
3aюnoчитеЛЫ:ffilМ 'тагом будет соэдани€ Dрилож~я Wfndows Jfurms, ROторое
позволит пользователю выбрать подlt'Jоочаемый блов с помощью стацдартното
диалCi1'.овоrа ОКНQ ОТКРЫТИИ файла Windows. Создав Щ)вое ПРИ!}J(~.жевие Windows
R>rms (е именем MyExte.ndabl.eAppl. добавЪ1,'е ССЫЛ!\у на КОМПOl:ювочнъm блок
СОI!шюпSпарраblеТуреs .dll. но не усmt:lfЩВJ/.щюi1me ссъmщ на БИБJЩртщm про
rpaммнoro хода СБ'hаrрSnарIп ..dll и VbNetSn:apln.dll. По~ о тОм, ЧТО це..ThЮ
ооа,цзвив этого прп.ilОЖенйЯ является ДеМонстрация динамичеС~ОI·О· связывани.яи
return fоuлdSnарlП;
)
.....
i f (t != Bu ll )
{
r e turn fоuлdSларlП;
1/ Вызод данных.
f o r e ach (CompanyInfo Att r ibute с in customAtts)
(
Me s sageBox.Sh ow( c . Url,
s t r iBg. Format ( "Д о п о лнит е льные сведени ... о (О} ищите по адресуП,
c .Name)) ;
Резюме
Сервис Dтображения оказывается весьма И11тересl'JЫМ асцектом прстроен;ия
надежного окружения при иcnользоваltИЯ объектно-орие1tТИРоваиного подхо
,да, 8 среде .NEТ 'Ключевыми элементами сервиса отображенИJt -Яlmяются тшт
Syst.em .туре 1'1 пространство имен Sу s t..ещ.Rеf.lесtiод. Отобр<Щ\:енне upедставляет
собой ПРоЦесС выяснения ОсноВНЫ'х харaкrеристик и ВОЭМОЖJIосте,Й типа в среде
ВЫJЮлнеН!ИН.
ДинамичеСкое СВЯЭЫВaJ-IИ:е предполагает СОЗдaRИе типа и вызов ето 'ЦI~JЮВ при
отсутcrвия априорной юtформаций о IЮI-пq>етны.х. им;енах соответствующц.х ~
.вов. Как показывает пример создаваемого в ЭТОЦ rлаве расщиря.емрго ПРЦJlOже
.н:ия. ато очень мощн:ая техпика. которая МОЖIП ИСЦОЛЬЗ0ваться JЩR созщш'елями
Замечание. Если столбец РID в окне Диспетчер задач Windows не отображается, выберите в
этом окне команду Видr:::> Выбрать столбцы ... из меню и в открывшемся после этого окне уста
новите флажок ИдентИфикатор процесса (РID),
Обзор потоков
Каждый процесс Win32 имеет один главный "поток·. выполняющий ф)'НIiЦИИ
точки входа в приложение. В следУЮщей главе будет выяснено. как создавать до
полнительные потоки и соответствующий программный код. применяя возможно
сти пространства имен System.Thr:eading. но пока что для освещения вопросов.
представленных здесь. нам нужно выполнить определенную вспомогательную ра
боту. Во-первых. заметим. что nОnЮК- это "нить" выполнения в рамках данного
процесса. Первый поток. созданный точкой входа процесса. называется neРВllЧН:Ы,м
nоnюком. Приложения Win32 с графическим интерфейсом ПОДЬ30вателя определя-
[лава 13. Процессы, домеНЫ rтРИJ10жеIiИ", ""Оljте.ксты И lCо.ст.ы ClR 539
ЮТ В качестве точки входа приложеНЮJ метод WinMa in (), I\щrсоm.ные пршюжemm
ДJIЯ 'ЭWОЙ цели ИOllo.nъауют метод Main Л ' Процессы. соетОIlЩИ.е из ОДНОГ() первично
го пОТока.. БУдУт n011'lOкоуctnоUЧuвымu. DОС1<ОЛЬКУ Б них В ~amдbIЙ момент' времени
талыш один .nото!( может по.JIYЧИ'ТЪ доступ J{ даиным приложе.~. Однзи@ одно
поточный процесс (особенно есJtИ он оснрван На графичесЮi)М интерфеikе) ча ~т о
бывает "с:клонен:" не Отвечать пользователю rrри вьmо:днении ДОТРАОМ до("т~точв о
Сло-ЖНblX. действий (напрJIМtф. связанных с печатью БОJThЩОГО теНСТОБОГQ фqЩ;;t,
зan;yтaнным;й В:ЫЧ:ИС.J1ениями или ПОnЫТR8.МJ1 соедиnитJ>CЯ с удаленmцм ce-piВ epoM ),
'Учитывав .9Т1'I rtotel-ЩИальны~ недостаТItи однопоточныx приложений, W'in32
API позволяет первИ"IНЫМ потокам пор~mдатъ допо.дцителЪНР1е вторичные потоки
('1:'d'Rже называемые рабачuмu ГlOтaKaA1U). используя. нщrpимер, такую удоб~ую
фymщи.юW1n32 APi. как CreateThread (!. Каждьrй ПОТОR tпервичнъ1Й шrn вторич
ный) в таком процесс е стеновитсn унивальным элементом ВЬПJQЛsенJiЯ и по~ ает
дpeтyn JЮ всем Oтn.-pы'ГЫМ эдеме:нтэм JIаБНЫХ на УCJ.IОБИЛХ .lЮнкуреяции-
Поток Д Поток В
Взаимодействие с процессами
в рамках плаТфОРМbI .NET
Хотя процессы и потоки сами по себе не являются чем-то НОВЫМ, способы вза
имодействия с этими примитивами В рамках lDIатформы .NEТ существенно изме
нены (К лучшему) . Чтобы успешно пройти путь К пониманию npиемов построения
КОМПОНОВОЧНЫХ блоков с поддержкой множества ПОТОКОВ (см. главу 14), мы начнем
с обсуждения возможностей взаимОДt"..йствия с процессами на основе использова
ния библиотек базовых классов .NEТ.
Пространство имен System,Diagnostics определяет ряд ТИПОВ, позволяющих
программное взаимодействие с процессамИ, а таroке типов , связанных с диагно
стшtой системы (например, с журналом реrистрации системных событий и счет
чиками производителъности). В этой главе мы рассмотрим ТОЛЬКО те связанные с
процессами типы, которые определены в табл. 13.1.
1
r
542 Часть 111. Программирование компоновочных блоков .NET
Console.WriteLine("************************************\п"};
1
т
theProc ~ Process,GetProcessById(987);
catch
Console.WriteLine("************************************\п");
Чпек Описанке
Bas.e Priori ty ~итает значение бваового ПРИОРl'Iтеrа nOi:dKa
С,пr rэГ!.,t Pr w ri t y Читает ЗНl;iчеltие l'е куще ГО' flриорит~та пот()~
ld Читвет УJ1Иl(альный и.tJ;енrификатор потока
ldealProc.essbr Задает tlре.щю"ггителЫ-IЫЙ Flроцеосор Дд'Я вl>IIJDлнения данного потока
Рriфrl t:iLeve 1 Читает JAЛИ задает YDOl;lfillib пРМРИ1'ета для ;ЩЩНОГО Г1{)1ока
Рrос:еS,ЭQr1l.ftini ty Задает процессор6l, на которых может ВЫПОЛf;!ЯТЬСЯ асоойиирое8НН ЫЙ
поток
Перед тем как двиrаться дальше. следует заметить, что тип ProcessThread не
я.вляется. тем элементом, который можно использовать для создания. остановки
или ликвидации потоков в рамках платформы .NEТ. тип ProcessThread является
средством получения диагностической информации об активных потоках WinЗ2 в
рамках ВhlПолняющихся процессоа. То, как строить МНОГО поточные приложения с
помощью пространства имен System.Threading. мы с вами выясним в главе 14.
catch
Console.WriteLine("************************************\п"):
catch
Сопsоlе.WritеLiпе("МодулеЙ не обнаружено!");
Глава 13. Процессы . домены 11РиложеНI:1И , KOHTe·K.~ТbI и JtOCTbl CLR 547
Чтобы увидеть IIРИJ\«ер :ВО:jЫф~ОГО B:ЫВOД~ прегpёlММЫ, давайте прОверим 33-
трущенные "N:ОЦ)!'ЛИ ДJШ лроцесеа, ~I:,ЦIОЛНRеМОFО "в рамках рассматриваемого здесь
JtOHCOJ1bl30ro rqmложеI!ЩI Process]'1a,nip,J1.a tor. для этого запустите npилОжение.
вьmс.щrте ;:sнаЧСЮiе РШ. СОО1'В~ТGТвующее. PrQge~sManipulatQr. e~e.· и передайте
это ЭЮlif;lе-Flliе методу Е ourrtr>1о q;sForp id () [не забудьте соответствующим обрююм Dб
навить метод. Mai [j О). ВЫ, навернре, УДИЩ'll]1ееъ. увидев .весь СПИ<:ОК мод.УЛей *, dll.
иоторые иеtlользуюте,ц для ТЩtОГО цростого RЮНГ'ьЛЪНОro пр:иложенил (а t·l. dll,
mfc4.2u .dll. o1e-a.ut32.dll и "LЦ.). на рис. ЦJ~5 IIО:казан результa'I запуска.
public ProcessStartInfo();
public ProcessStartlnfo(string fileNarne);
public ProcessStartlnfo(string fileNarne, эtriпg arguments);
public string Arguments ( get; set; J
public bool CreateNoWindow { get; set; }
public StringDictionary EnvironmentVariables { get;
public bool ErrorDialog { get; set; }
public IntPtr ErrorDialogParentHandle {get; set;
public string FileNarne { get; set; )
public bool P,edirectSt.andardError ( get; set;
public bool P,edirectStandardInput { get; set;
public bool RedirectStandardOutput { get; set; }
public bool UseShellExecute ( get; set; )
public string Verb { get: set; }
public string[J Verbs ( get; )
p1.lbl ic ProcessWindowSty 1е Wi rldowStyle { get; set; }
public string WorkingDirectory ( get; set; )
public virtual Ьооl Equals(object obj);
public virtual int GetHashCode();
public Туре GetType();
public virtual string ToString() i
11<1 приведе:нцorо списка следует. Ч:ГООДИН процесс можer содержа:гъ любое. чис
ло до:м!що~ ЦР,Wlожения. кажДЫЙ.из IШторых лолнЬctЫD изолирован от дрyrи:х до
менов ПРЩlDжения в рамках данного працесса (а тю,же любого другото процесса),
с учетом; 'этого QЛедует ПОfIИ1l.1аТЪ.ЧТо прИhoженй:е. Вbll10лнлющееся в одном домене
r;rpиложещrя, не может пo.nyчить данные (В чаСТНОСТИ. значеииJi глобмьНblX пере
меfШЫХ JfЛИ с:;.татнчес:ких полей) дpyt'oгo домена ПРИЛО1Кенияина Llе, :Как с ПОМОЩЬЮ
протоI:ЮJIa удаленного взаимодействия .NEТ (кОТОРЫЙ'МЪ1 pacc.мoтpKl\l1 В главе 18).
ХОТИ одцн процесс и МО'жеmnршш'lЪ .МНожество ДOM€HOB npИЛd)!reния.Т€Щ бы
~ёJ,eT не всегда. I{aк минимум, процесо ОС буДет содержать то, что обычно наз1Ц8Э
ют дq:М.СfЮМ Г!рШJOжен.Шl. соааанным Jio !jМDЛtft1Н.шо. Этот специалышй домен np.и
JJЩft~,нщr автоматически создается средой CLR во время :JanyCl(a процесс~.
После этого CLR ,создает ДOD'ОJIJШтелъпые домены прлложения по мере необхо
Дl'iМрСт,и ., Если тю'I'peбуетс.я (хот.l1 ото и маловероятно). вы можете программно соз
дa,в~тъ домены npиложенин: всредевlШIОЛНения в ,рамках БЬШ(jJI}1ЯемQГQ npaцe~ca.
1
--
550 Часть 111. Программирование КОМПОНОВО'IНЫХ блоков .NET
Член Описание
Событие Описание
Списокдоменовприложенияпроцесса
Для примера программного взаимодействия с доменами приложеfJИЙ .NET
предположим. что у fJac есть новое КОfJсольное приложение С# с имеfJем
AppDomainManipulator. в рамках которого определяется статичес}(ий метод
F'rintAIIAssembliesrnAppDomain (). Этот вспомогатеЛЬfJЫЙ метод использует
АррDоmаiп.GеtАssеmbliеs (). чтобы получить список всех двоичных файлов .NEТ.
выполняющихся в рамках данного домена приложения.
ad.F:riendlyNam!;) ;
f·oreacll (lis semb1 у а in 1 oadedt\ssem1H i ез)
{
Co:t1so1.e. Wri teL.i.ne , .. -::;-i'O J 11, а. C;l2tNa1!(8 () . Name) ;
.ммя.:
Сол·sоlе .• Wri teLir:re("-> Версия·; (\)} \0", а.G>:>tNаше (i.VersiOl1-);
СОГlsQ·l-е. Rea.d'I,illE: () ;
На рис. 13.6 ПО1'(~Зан СОOТIlетству.fPпnЩ ЕЬЩОД (номера версий у вас мотут быть
дрyrими).
АррDОШ&ibИaniРUlаtоr,ехе
' ~j
:. =========~I
5ystern, dll ,
j,.::=:==========~
1: ;u"ЦЬr-аJ;,у ,dll
,,--_Арр_'.__l)_o_ma_i_-n_МIffi_i_р_l.й_а_t_Qr_,_е_х_е--' '1
событий.
ПРоцесс .НЕТ
~ !f~ !tnmIiШr
I Гt0У~1O ] I nO ·.Умo:nч8Ю'll&
I I по yмr:ifP'I8НИЮ ]
~1 .ICoнr~1
I I 1 I
Кoктeкcr~ ] КotmIкct2
I I I
РиО', 13.9, ПРОЦООСЫ, AOMt)HЫ ПРИ11ОжеtiJl1R и границы контекСта
1
--
556 Часть 111, Программирование компоновочных блоков .NET
...
Глава 1З. ПроцеССJ>1, домены nр.ИЛDжениЙ, контексты и косты CLR 55.7
3аМ81f8НИ8. В ЗТО~ ICI1Иге 101& ра.СQматриваютоя П0дро6~JОСТИ I:оздан'ия ЬОJlЬЗователI:ICКИ)( ",онтеКСТОII
обьвlCТОВ, но если вы заинтересованы узнать 'об этом БОЛI:iШВ, nРО'lmайте Kl'J)I1ry App/ied .NEТ
Aitr/butes (АрrеSЭI 2003),
1
558 Часть 111. Программирование компоновочных блоков .NET
I
Обратите внимание на то. что каждый конструктор получает тип Context от
текущего потока выполнения через статическое свойство Thread.CurrentContext.
Используя объект Context , вы можете распечатать информацию о границах кон
текста , например. значение ID контенста или значения дескрипторов . получеюIЫX
через Context.ContextProperties. Это свойство возвращает объект, реализую
щий интерфейс IContextProperty, который обеспечивает доступ к дескрипторам
с помощью свОйства Name. Теперь обновите метод Main (), чтобы разместить по эк
земпляру каждого из типов класса.
r
Глава"IЗ. nроцессы, домены прилож~ний, КОfJТfЩПbl Jd XO(JТЫ CLR 559
для JI\JП"сеа SportsCar не бьmукаэ2Н a-I'РИбyr IЮНТe:J<CТа. поэтому ореда CLR раз
мещает spo.rt sport2 в кoнreKёTe О (т.е. в KoнтeКC"J:e. СQздашюм цо умолчанию).
tI
ОДНaIW объект Sport; sCarTS аатружаетс:я. в овои уншщ)lыIыIe КОIn'екстуадЫfше гра
НИДЫ (:КOTOPhIМ назначается и,центифИftатор 1). hОСКОЛЬку для этоrо ИОWГeRСТНQ
СВНЗaIOlоготида был указан атрибут ['Sупсhrоni,zаUоn].
ПQсп.е загрузlUi ms с;: а!: е'е . dl1 по реестру еис~МЪ!1. Wln32 (да, па p~ecтpy эmoй
СПQтеМЫ) ВЫЯСНЯетс& 'номер последней из устанf,)вл~нных версий 'И путь устанОВ
ю, .NET Fгame:work (ИСПОJIЬзуетс.я В-е1'вь HKEY_LOCAL_MACHINE\Software\MI'O rosoft\
.NШrаmеwоrk, рис. 13.1'2).
13 10 Мi<rosoft.NEr
S ·~O Fr amework
0,,1.0.3]0,
Ii Q _l.1.4322
IE Q "2.0.4ОБО7
Все это происходит незаметно в фоновом режиме и только тогда, когда извест
но. что обновление обеспечивает правильное выполнение. В редких случаях воз
никает flеобходимость заставить тэ coree. dll загрузить КОНlсреmную 13ерсию CLR.
и тогда вы можете использовать ДЛЯ зтого файл *.config клиента.
<?xml version="l.O" encoding=»utf-8" 1>
<configuration>
<startup>
<requiredRuntime version ="1. 0.3705" />
</startup>
</configuration>
Здесь элемент <requiredF.untime> указывает, что для загРУЗRИ данного компо
ново"шого блока следует использовать только версию 1.0.3705. Поэтому. если на
целевой машине fleT полной инсталляции .NEТ версии 1.0.3705. конечный пользо
ватель увидит окно с информацией об ошибке среды выполнения. показанное на
рис. 13.14.
о
111 "'" tI1iS appb1ion, YCU ~st mцotnllll_ of tho! fiIIOiOМng _ _ af tho! .I'EТ ~k:
,,1.0.3;105
СantoЮ 'fOAJf i!1P1111a11ian ~ fiэt i'IS~ m.tobtalning tho! ~ _ of """.NEТ Fr"""""orI<,
] Сообщение гласит: "Чтобы въmолнить это приложение, установите одну из следующих вер
сий .NEТ FrameWork: vl.О.З705. Обратитесь к разработчmty приложенИfI для получения ин~
струкций по поводУ установки нужной версии .NEТ Framework."
ГЛВflЗ 13. ПРОцес.с;ы, домен'ыгтрильжений, коНтекстЫ и )(OCrl>! CLR 563
Резюме
Целью этой гдавЬТ было выяснение Тмо. какобрабатыва.ется ВЫnOJIНи.е~I,Й об
раз· .N.ET. Вы ИЪJМИ !ЭО3МОЖВ:ОСТЪ убедиться в '1'ОМ, что ~e привычно е повят.ие
проце~са Wir132 было 1щутренве иЗменено с тем. чтобы адаптировать его к тре
бованиям CLR. ОТДf'J~Ы'J,:ый пр(щ~сс (коТОрЫМ MOmнO nPОJ:'раммноynравлятд с по
МQЩЬЮ ТИllq S,ystem.Di.,.grJ()st,j:cs.Process) теперь компонуется из множества .до
менов црилежеJШЛ, И]IoJ,еwщих изолИрованные и !reЗавясимыf' rрaJUШЫ В рамках
В
мы .NEТ
предыдущей rлaве мы рассмотрели roaимосвязъ меящу процессами. домена
ми DpИJ1ожения и :коите:КС1'ВМИ. В этой MJ>l ВhlЯcнm.~. ка:к 11 ра:мнах JJШJТфор
crp01fib мноrОПОТ(Jчные ПРИЛQже:юm и как в УC.IlОIЩЮ!: :множества потоков
гарантироватЬ целоcrность совместно и~полъзуемых ресурсрв.
Наше обсуждение снова начнеТСIfJ с раС'смотрения ТЩJа деле'f'ата .NET. что
бы rIpИйти 'IC пониманию его внутре:н:uей поддерЖR1-1 асюаронных вызовов ме
ТОДОВ. Вы УВИДИ1'е. что такой подход позволяe'r а:&томаТJj'чесни вызвать метод во
вторичном потоке ВЫПD.'JНения. Зате'М мы исследуем "J;~IIbl прос-rpаБства имен
Sуstе·m.Тhгеаdiпg. ву.дет рассмотрено множество ТjIПО~ {1'.iJ read. ThreadSt.a:rt
и т.д.l. noзвотnoщих с лег.костыo создават& дonщIIщтe.rrы;[bl~ ПQТО1Ш. Конечво. слож
носТь разработки МИQrопоточных при.ш)ж~ ЗaJЩ19чаетСА не в создании поroиов.
ав гарантии того. что ваш npоrpaммIO;IЙ J(OlJ,' будет иметь над,eжgые средства обра
ботки вонфликтов при нощуренmОМДQстynек общедос'I}'IIНЫМ ресурсам. П(!)этому
завершаете!! тава рассмотреЮfем раЭJl)fЧ»blX примитивов синхронизаЦии. пред
лагаемых каркасом .NEТ Framework.
1
566 Часть 111. Программирование компоновочных блоков .NEТ
Любой поток в любой момент времени также может быть перемещен средой
CLR в любой из имеющихся ROHTeRCТOB ИJШ помещен в новый контеКС1: Чтобы по
лучить текyIЦИЙ контекст. в рамках которого оказался поток, используйте статиче
ское свойство Thread.CurrentContext.
private static void ExtractCurrentThreadContext()
{
11 Пon:учение контекста, в рамках которого
11 действует текущий поток.
Context ctx = Thread.CurrentContext;
Снова подчеркнем. что именно среда CLR является тем объектом, который отве
чает за помещение потоков в соответствуюrцие домены приложения и контексты.
Теперь Бам д.олжно бъггь яCEi:о, что домены м"ногопоточного приложею",я тоже
открыты ~;Щ:Лf~ИЮ цоТORов. 1IОСКОЛЪКУ Потоки могут пытаться ИСПОЛЪЗ0ватъ дocтyn-
1Щlе фУ~ЦЩИQнальные возможности одновременно. Чтобы ЗaJiЩТИТЬ ресурсы npи
ложеl'lЩJ ОТ возможных искажеШIЙ, раэрабоТЧИЮlМ .N'EТ Прщmдится и.сподьэовать
тещ наз~аемые npимитивы rют.аков (т.ш<ие. :как блОЮIpовки., мониторы И атрибут
[5упсhr~:Юizаtiоn,JJ, ЧТQбы КоНтр<шировать дocтyn въmолня:еМЪJX ПОТОlЮВ.
Цельзя утверждать,. ЧТСI шrarrформа .NЕТИСЮПОЧlma все ТPY,/IНOCTJJJ ВО3.IO.1.EaЮ~
"1.ЦJ}C :цри прстроении устойчивых МНОГfШОТО-ЧНЫХ ПрWlоженml. 11.0 теперl, этот про
цесс э!щчител.ьно ynpощён. Исполъэуя ТИIIЫ. оn'pе.целеЮihtе в ПРОС,транетве имен
:5У'5 tem. Тhrеаdiпg,.вы: получаете БО3МOЖ1iостъ создавать , дополнительные ПОТ01m с
'МИШШaды1blМИ усилиями и МИНИМЭЛЬНЫМИ проблема:ми. Точно так ~" иorда npl'1~
Jl;ОДИТ IIpeМfl блокировать or.гкpьtгыe элементы данн:ы:х. Бы.можете иcnол:ьзовэ.ть цо
ц~тельные типы. :которше обеспе~т -ге же функциОНElдЫ'Iые возможцоети.
что и: прпмитив:ы потORО:В WlnЗ2 АР] (НО при этом используется Ha~HOГO более ах·
~а11Наяобъeюwш модель).
Однако и.спользование пространства имен sys,t em.Threa:dipg - это не един
пвенный путь построеmш мнQгопоточпых програм:м .NEТ. В ходе нашего обсуm-
568 Часть 111. ПрограММl1рование КОМПОНОВОЧНЫХ блоков .NET
дения делегатов (см. главу В) мы уже упоминали о том. что все делегаты NEТ об
ладают способностью асинхронного вызова членов. Это - главное преимущества
платформы .NEТ. поскольку одной из основных причин. в силу которых разработ
чик создает потоки. является необходимость такого вызова методов. при котором
не возникает блокировок (т.е. имеЮiО асинхронного вызова). Для достижения та
кого результата можно использовать и пространство имен System. Threading. но с
помощью делегатов это делается намного проще.
/ / Тип дenе:roаo:rа С •.
public delegate int BinaryOp(int х, int у);
Замечание. Если асинхронно вызываетСя метод. который ' Не r:lредлаrает 'возвращаемblX ЭI:1ЭЧ!ЖИЙ,
МQЖНО' \'jrq BI;>I;3Baтb И пPwТО "забыть· (1 нем. В таких [}дy"tВЯ'Х f1eT неОбхоДИмЬС-ти СОХР8J:IЯJЪ CO ~
ВМt';CtимЫй С If1..З yncRe:SiJl t об'l;jвкт и .8ыыы1з:ть·· E'!Lctln:voke () (TaI< кa~ нет возвращаемоrо
зн~ченIo1Я. которое rpe(jyercfr иэвле%.) .
Выполнив это приложени:е. вы увидите. что теперь выводятся два разных хеши
рованных значения. посколы<у в границах текущего домена приложения выполня
Рис. 14.2. Методы, вызываемые асинхронно, выполняют свою работу в отдельном потоке
BinaryQp ::ь =
new ~i.na~yOp (.Аdщ I
IAsyncR~sult iftAR = b.i!e.giI1Invoke(10, lO, null, nblll);
паmезрасе AsyncCallbackDelegate
(
public delegate int BinaryOp(int х, int у):
class Program
(
static void Main(string[] args)
(
Console.WriteLine("*** Пример делегата AsyncCallback ***"):
Console.ReadLine() ;
Тип Опис~ние
lnte:rlocked Прэд.nаГQет a-tомарны~ оneрацИI-1 д;I1\1 ТИnQВ, алФьпы)( д,ля MRO-
mecrвa потоков.
Член уровня
Описание
экземпляра
?riority Читает или уотанавливает приоритет потока, которому может быть 1-1а
значено зна'lение из перечня ThreadPriority
ThreadState Читает информацию о СОСТОЯНИII! потока, которая может принимать зна
чения из перечня ThreadState
Abort() Дает указание среде CLR завершить поток как можно быстрее
start () Дает указание среде CLR как можно Бытрееe начать выолнениеe потока
Suspend () Приостанавливает выполнение потока. Если поток уже приостановлен,
вызоа Suspend () ипюрируется
Глав(! 14'.Созлsние, MltOranOfD't!ibjX ГtРИJtОJkени,й 579
Свойство Name
Приведенный выше прогрaммный код достаточно понятен. но обратите внима
ние на то. что класс Тhread предлагает свойство с именем Narne (имя). Если вы не
установите для него значения. свойство Nam.e будет возвращать пустую строку. Но.
назначив данному объекту Thread в качестве имени понятную строку. вы можете
сильно упростить процесс отладки. В Visual Studio 2005 в режиме отладки можно
использовать окноThreads (Потоки). доступ к которому можно получить. выбрав
DebugqWindowsqThreads из меню. Как показано на рис. 14.6. в зтом окне можно по
имени идентифицировать поток. который слеДует проанализировать.
•
ть .,,,а. IEI
Свойство Priority
Далее заметим, что тип Thread определяет свойство с именем Priority. По умол
чанию все потоки получают приоритет Normal (средний). Но вы можете изменить
зто значение в любой момент времени существования потока, используя свойство
Priority и связанный с ним перечень System.Threading.ThreadPriority.
public enum ThreadPriority
(
AboveNormal,
BelowNormal,
Highest,
Idle,
Lowest,
Normal, / I Значение r испo.n:ьзуемое ПО УМОJIчаНИl).
TimeCritical
5, ВЫЗОНИТt": метод Thread .• St·art (). Это у.каза;ние КaI:t ~ОЖН:О быстрее старто
вать nWOK ДЛI:I метода. на щ>торый ссылае'J'C1l, делегат, созданный на шаге 2,
11 ВЬп!iод чисел.
Сопзо 1е. Wr-i te ("Ваши числа: ");
for(int i = О; i < 10; i++)
(
Console.Write(i + ", ");
Thread.Sleep(2000) ;
Console.WriteLine();
Теперь в Ма! п () нужно предложить выбор одного или двух потоков для вьmол
нения задач приложения. Если ПОЛЬЗ0ватель выберет ИСПОЛЬЗ0вание одного по
тока, просто вызывается метод PrintNumbers () в рамках первичного потока. Но
если пользователь указывает два потока, создается делегат ThreadStart. указыва
ющий на PrintNwnbers (). Объект делегата передаетс.fI конструктору нового объ
екта ТЬ read и вызывается метод Start () , информирующий среду CLR о том, что
поток готов к обработке.
Сначала установите ссылку на компоновочный блок Sys tem. Windows. Forms . dl1 и
с помощью MessageBox.ShQW () отобразите подходящее сообщение в Main () (смысл
этого станет ясным при запуске программы). Вот полная реализация Main () в нуж
ном виде.
р. Рl::intNшrtbе Т 5 ('};
b r-ea k ;
def .. u lt :
COJ1So1e.Wri t e L3. neC"B.aIJГJo'! ,указания не яс ны ... буд ет 1 nо::г'о:к.");
goto c-a.se п 1~ ;
Если теперь запустить эry nрограмму е- ОДi[-ЩМ потоком, :ВЫ оБШЧiJу~те. 'ЧТО.
ошю сообщения не будет отображенО. до тех пор. no:a:a на ~ОНСОЛЬ :J;Ie б3lдет Bыеде--
на вся последовательность чисе..1L Здесь бь{щ! YJЩЗa}Iа пауза npиб~JIТельно в две
секунды ПОСJIе вывода ка,ждor,() иа чи:сел:, поэтому цодаБJ'lQe повеД~е программы
не вызовет восхищения коIreЧНОГD пользовате.rlJ{. Но ес:1IИ вы 13ы6ерете ва,риаl'I't с
двумя IЮТока.1\Ш. окно сооБЩеШ1:Н появится .вемедденно, посколь~ дл;я вывода чи
сел ffi} IЮ1iСОЛЬ будет :ш.:пользова'tЬея свой ующадЫIы:ИобъеR;Т ThJr1ea'd '(рис . 14.7).
1
584 Часть 111. Программирование компоновочных блоков .NEТ
запуске этого npиложения с использованием как одного . так и двух потоков числа
class AddParams
pub,lic int а;
public int Ь;
1
586 Часть 111. Программирование компоновочных блоков .NET
Thread bgroundThread =
new Thread(new ThreadStart(p.Prin t Numbers));
bgroundThread.IsBackqround = true;
Ьgr о uЛdТhrеаd. S tаrt() ;
СОП$оlе. WriteLin_e () ;
class Program
{
s',t at.Lc void Main( s tr'illg[] ilrgs:)
j
cousru,e. Wr 1 t-еL1 r.e ( Ну ... " *'* Синхронизаu,ия. ПQ'rСУ<оСНJ .. ~,~ '" *\I! '7! :
Перед T~M «ан вьtnОJIНI:IТЪ Тестовый запуск про,граммы, давайте обсуди:м :со,
оrnет<:твуюtцyю npобnему, Зд.ес:q первИЧНJ;!Й поroк в p~lIofКax домена прилоЖt1НИя
порождает десять ВТОРИЧНЬJX рабщпцr. ПОТОООВ'. ~oмy рабочему потону дается
ур;аэание въtзват-ь метод P.rint_Numbers () одного'J;J ТОГО же эн:эсм:гumра P,r-i nt er.
ПОСКOllli;НУ ЗJ];есь не предпринято НlЩaIOЦ( мер по блоки:рованию 6бщедостynныx
ресурсов дш-uroго объекта (КDНСQЛl~). имеется болъш;i!Я веро.ягтоСТь ТОГО, что ТеЕу'
щий поток бу)];С'Т npиостан;овден до 'Г0ГО-, 1ЩК метод P"rilltblum'b 'e rs _() зaEmiЧИТ вы·
ВОД BteX своих реЗУJlI;I'Гатов. Бh\ лезцаете точно, :когда это СJ1YЧW.IЪСЯ (:и случитс;я JП'I
ВQобще). поэтому Е)'ЖНО быть WТФ:ВЫМ к непредвиденным реэулвтатам. Например,
может ПtiJ1y'-ШТLСЯ BlЦBOД, показaн:ный на рис,. 14.8.
ВЫПQЛIПIте прююжение еще lIf"CКОЛЬИО рЩ!. на рис. 14.9 ПOItазана ,цpyтaFI воз
можность вывода (вапщ результаты. очеВJЩНО', тоже буд.Y'r' цpyrими).,
~
588 Часть 111. Программирование компоновочных блоков . NET
Ясно, что проблемы здесь деikтвительно есть. Каждый ПОТОI< дает указание
объекту Printer печатать числовые данные, и планировщИI< потоков запускает
выполнение этих потоков в фоновом режиме. В результате получается несогласо
ванный вывод. В этом случае мы должны программно организовать синхронизо
ванный доступ R совместно используемым ресурсам. Нетрудно догадаться. что в
пространстве имен System.Threading есть целый ряд типов, имеющих отношение
к синхронизации. А язьrn программирования С# предлагает специальное ключевое
слово, как раз для решения задач синхронизации совместного доступа к данным в
многопоточных приложениях.
ГМва 14. C03AВH~e Мl'ФiОП0ТОЧНЬ)Х ГJРИJ10жен.иЙ 589
З8МfJlfакие. ЕслИ У вас не получается mHep~Ol!aТb непреДl!идеННI>1i11 8МВОД,. 'увеличьте 'Iиело
потоков с 1О ДО 100 fнаПРИМ6Р) и1tИ добавьте в свою программу вызов Thre:a d. 51 еер ( ) .
,8 kOtЩе концов. 8ывсе ра'вно СТОllкнетесь с проблемой КОНКУРЕЩlIНQГО Д{)СТУГJR.
вого СЛОВа 19~k. Это НЛ:ЮЧeJ30е слово позволяет определить XORТ~кcт' оператDpОВ,
:которые ДО.JJ;ЖНЫ СИНХрОНИз.И-РGВaТЬСfl междУ IJОТОКСЩИ. В реаупьтате ВХОДJIЩИе по
ТОКИ не cмoryr прерватъ T~ ПОТО:К. пока 01f выполняет свою работу, Ключевое
СЛQВО lock требует. чтобы выуказaJIИ мщжер ,(объектную ссылку). который потре
буетс-я- rт.oToвw ддя входа в предеJJbl КОНТl'Щста lock. При блоиир.овке метода урcmня
<шземrшяра МОЖНО шшользовать просто ссылку на текущий тип.
1/ ВlDtOД ЧКСIIJJ.
ССФ~..юlе. ,Writ·е ("Ваши числа ~ П);
fOI' (int i = D; i < 1 О; i ++)
I\€1.лdоm
r = new Random () ;
Sleep (1 ооЬ ... r .1'Iext (5 J)
T,Me-ад .. J
COh$ole.Write(i ~ ", ");
)
Cansol-е.Wri't.еLinе()t
J
590 Часть 111. Программирование компоновочных блоков .NET
Замечание. Если пытаться блокировать программный код В статическом методе, в 1:>1 , очевидно,
не можете использовать кпючевое слово t h i s, Но в этом случае можно передать объект
System. Туре соответствующего класса с помощью оператора С# type o f,
Если снова вьшолнить это приложение, вы увидите, что теперь каждый поток
получает возможность закончить свою работу (рис. 14.10).
COnSble.Write~in~f};
:Еillэl1у
!
Nanitor.Exit(this):
Член Описание
нии. Предположим. что у нас есть метод AddOne ( ) , который увеличивает целочис
ленную переменную intVal на единицу. Вместо программного кода синхрониза
ции, подобного следующему:
public vo id AddOne()
(
int newVal = Interlocked.lncrement(ref intVal);
public v oi d CompareAndExchange()
(
/ / Если значением i IIВЛ5lе'l'С51
83, измени'1Ъ еl'О на 99.
Interlocked.CompareExchanqe(ref i, 99, 83):
i Глава 14. Создаftие .tlНоrоnотnЧНЫХ прИ11ОжеtМi 593
Проrраммирование с помощью
таймеров обратного вызова
Во многих цриложения:х ВОЭН1Щает flеQбходимьсть вызывать КОНRрет.яый M~
ТОД через р~гул:ярные ПроМежутхи времеlUl, Нащщмер. в одном qpWIOжении 'МО
жет ПОТребоваться отображение тещтщего времeIЩ в строке соетоl'Il:ЩЯ с ПОМОЩЬЮ
неК6ТОРОЙ вапомоrа1'елъной фушщии. В другом приложещrn може-т цонадобпты:я
IIерподичесю-I'Й ВЫЗОВ вспомогательной фущщии. ВЬЩQшщrощей ~ фЩIOВОМ режиме
какИе-то .неRри-rич:ески~ эадач:и, например DpШЩРl\}7 rlOcтyтre;mцJ цoBыx соqбще-
594 Часть 111. Программировани~ компоновочны)( блоков .NET
ний электронной почты. Для таних ситуаций можно использовать тип Sу s t ет.
Тhгеаdiл g .Timer в совокупности с соответствующим делегатом TimerCa l lback.
для примера предположим, что нам нужно создать консольное приложение, ко
торое ежесекундно выводит текущее время, пока пользователь не нажмет клавишу ,
....
i
Глава 14. GО3Д8.н.ие миотОnОl'ОЧНЫХ Приложений 595
sta'tic void Print'I'ime (Qpject st;ite)
{
Console.WriteLineC"BgeUR: i O). ПарамеТi?~ \1J",
D<lte~ im-e .N'o\~. То LqfigТщев't rJ.ng
(), s ta.te . ToSui'ng (~ ) ;
class Program
(
static void Main(string[) args)
{
Console. WriteLine ("Старт главного потока. ThreadlD = (О 1",
Thread.CurrentThread.GetHashCode()) ;
Printer р = new Printer();
WaitCallback workItem = new WaitCallback(PrintTheNumbers);
/ / Очере~.. из 10 810130808 не'Х'ода.
for (int i = О; i < 10; i++)
(
ThreadPool.QUeueUserWorkltem(wo rkItem, р);
I!
Резюме
8та глава начадас:ь с рассм.отреП1fЯ -Гo~o. как настрои:гъ ТИП делега:r.a .NEТ 1Ja
вызов Meтoцo~ в асцJiXPОю;rоЙ' форме . К.ап бъшо поШiаЭНо. методы Begi:oIh'J'oke ()
и EndIhvoke (} ПОЗЩJ.rrюoт JWCJ3eHHO управлять фОНОВЫМИ потоками с минималь
НЪЩn ус;щrиями и ЦРaJ(тичес~и бе& llроблем. В .ходе обсуждеIn1Я БЬJlШ рассмотре
ны интерфейс l1\.syncResU1lt f[ тип класса AsуnсRеБDlt. Эт'И n-rпы обеспеtшвают
ра3.!Uiчиые· СПОСQбы СПВХРОfIИЗации :ВЫЗОВОВ И noлyченив: DОЗ.l1ращаемых знэчеНИЙ'
методов.
./
1
ГЛАВА 15
CIL и роль
динамических
компоновочных блоков
roВоря. при создании npогрзмм .N'EТ вПолне можно обоmисъ и без неnосредствеll
ного· и<!учения подробностей внутреннего устройства СIL-кода. ОДНaIЮ, изучив
основы CIL, вы получите более глубокое понимание того, кaI< функционируют s:e-
KOTOpЪJe Ммагические;' особеннос:тн .NЕТ{:например. меЖЪЯЭЫНО1Юе :наследование}.
Н CJставшейс,Я части l'ла:вы будет исследована роль npостранствз имен Syst€m.
Re"flectlon.Emit. Используя его типы. вы получаете возможность СТРОИТЬ rtpo-
граммиое. обеспечевие. способftое генерировать .кО:МnОИОlЮ"ШЫе бл.Оl.И .NEТ:в па·
мяти :во время выnаЛНiШИ:fl.. Формально ·комnоновоqИJ:;Iе блоки, определенные и
ВЫIIO.1IНяемые й rr.aм.яти. называют· дUf.tамuчес-кшиu KDMn0}-t080Ч1LЫМLI. б:тtoк:aмu. Raк
вы можете догадаться. эта специалыraJI :ВОЗМОЖНОСТЬ .МЕТ 1'ребует :шания Я3ЫJ{а
СП-. поскольку от вас потребуется УRазать набор CIL-ИlIС'l'pyКцrm. Е(}торые будУТ
использоваться пры С-uз.дании RGМПО:НОвоЧН'ого блока.
! n.e~, publiC, tJ'd,~ / Ьаэе: , 9e.t. S-el.. ~xplic:i't, 1.JI'!s-аfе, ёnU!!\, opet.C!t-o,r r pa.!t'tial!
Б;ы. cкQpe11: все:{'О. JifДеЦUlФI:Jj1:.Щpуere N. -И3:К IVIЮчеШ\J,C .слова язьmа с# (Ii это ира
В1IUmЛоJ. 'Но если ~ИСМQТРeтъt;Jl ~э:деменгЩl:{ зтor(} ЩJ.бора бодtx: .1IИИ'мательнu.-ВЫ:
CМ<'»R.eтe З!Ц4е'1'ИТЬ. ч.rrо 'ХО1i'Я i1дeC'~ ~r:й элеме.нт n .1ШJlяется k,o-почeвьtМ:
C:lIOBOU
CI, (1)}Ш иМеютщщершеН1if.Q pa2IНУЮ еемацтищг, Нanрпмер. КJ~чеВCJе dlOBO ЕШU!li
шrpед~ет ТИi1. прOIQВQДНЬ1Й от $:У8· t~щ.Е'РU:Щ, а ,JЩЮчевые c.rщ;ва thi$ п base пО
зв('JJIя'ют СС'I:iJlIз:гы:;а. еQОТS~тcrв~1ЩО~ на 'reJt.:'V'Щ}JЙ оБЪe.Iq IЩП р.одите.JIЬCRИЙ IL'I~
объехтз. RлкiЧroJОf:,('";ш;IВО ЩJ$р:U= иепо~с~ЦЩJ CQзр:щ-n;u;: бnока программноtQ
JЮда. Ete'гOpъm не Д~Ж~ неrщсрс:ДCТ1feщдJ RонтроJЩpова:ТI>СЯ средой Ct.R. ~ клю-
1:ffmоеСЛЩIО EJp~Tatoat ЛD3ЦОЛЯ~Т liцд:трmnъ CK!~ (~ElO IW.еновfШНьm)
L
Глаllа 15, Cll и роль ди1it8мических компоновочных fu!O«O!! 601
метод. который будет вызываться Totдa. когда вы .n;pю.tензете заданный оператор
С# (например. зшш сложения).
В ОТlШ'!Ие 0'1' TaROro высокоуровпевого языка. какС#. язьmСIt. не просто опр~
делает свой собственный набор юnoчевblX МОЛ. Набор леl(сем. понитныхкоМ1Пi1JЯ
тору CIL. разделяется:на три большие категории. в 3аВИCJ1Мости от СeмaJlТичеСRОГО
подтекста:
Но все же. что не может не радовать, некоторые KOДbI операций CIL в точности
r
соответствуют их аналогам в С# (это. например. Ьох. ипЬох. t:.hrow и sizeof). Вы
сможете убедиться в том. что коДЬ! операций CIL всегда используются в контексте
реализации члена и, в отличие от директив CIL. они никогда не обозначаются пре
фиксом. заданным точкой.
Mel.rтO"B методов. а таюке lДщей ~ типов. Н,УЯЦЮ С'начЕЩа ЯЩJО аатрузить эле
мент в Сl'ек. чтобы Затем "гыx0.IlКI:lYГЬ - его ОТ1'уда ДJ1Я далънеi):ш~Г9 исщо.ЛЪ30Вания
(помните о.б этом.. J'ieдb щ,IенНО поэтому fiiлон пр{)]:р~ого· ЩЩаСIL может казать
ея HeCHO.'1.blI;O нзбыТQ'ffiЫМ).
Чтобы понять. КЭIС CIL ИСПОЛЪЗУ~Т стековую М'oдe,lIЬ, рассмотрим простой
С1l-Метод F'rintМеЭSаgе [), КОТQРЬЩ не имеет ~pгyмeHTOB и ~ero не возврзщает.
В рам}ЩХ реалиЗдЦ:ИИЭТОro меТQд.а вы ~TO ElывоДите :iш:ачение лоЮШЫIОЙ СТРО
Щ)ВОИ пере~еш-IOЙ' в лоток стандаРТБ0ro вьmОДi!t.
• Перед вами стоит задача изменить компоновочный блок. ДЛЯ которого нет
исходного кода.
csc Rel.loProg-rаш.С5
.lIIDdul e Hel}0Progтa.ffi.e~
· irna\1~ba s е ОХЮ О 4 D:C!O О О
.ttle alignment ОхООООО200
.эtас k.l.·е-эегvе .C>X~ 0'100'OOO
.$ut)-s'y si;em ОхОООЗ
· сФг·flа,g.s О~ШОООО'ОQ1
,method' pi!:ivat~ hic1E;by~ig s .ta tic void MaL'1. ( эtI 1оч [1 args}
ci 1 mana.ged
1L 0012: ret
.maxstack 8
IL 0000: ldarg. О
1L 0001: call instance void [mscorlibJSystem.Object::.ctor()
Н, 0006: ret
lL (НН)с: са 1] .s.t r Lng [ffis cer l.:Lb] зуs tem,. Cohsol е; : ReadL.ine ()
IL-'1JОl1
; 'РР}?>
IL .0012: ТЕ,,;
• IJ1CLX:S tack. з:
I L_'0:0 !) О : 1darcl. О
11'_ О-ОО 1: C4lJ.l iЛ8 tаrщ'€i \J\Qid rms.cQr 1ibJ Sy:s t€1!! .. Qbj ect: : .oeter О
11, ОСОб : · ret
J
re t
I
t
Глава 15" CIL и роль динамиче~~и)С J(OMnOHD,SD"IHbIX БЛDКОВ 609
Итак. целью являетсв помещение I-IОВОЙ строки В с'тек и вызов мето,да
MessageBox...s'how (') (а не меТОДа Console. WriteLine О). Напомним. ~ при уиааа~
mrn имеии. внешнerо -пma слс:дует ИСПQl[ЬЭ,оватъ абсолютНое имв типа l» coвoнyn
~roсти ,С ПОН.R"ГНЬrМ именем 1ФМn01iOвочпоrо блова}. С учетом 'ЭТDго оБНОflите МетОд
Main (), так. ЮiI:it nа1Ш.Зано ниже.
,щеthоd p:ri'7at.e hideb,ysiS1 stiitiG \!,oid Main (,.н,rirЩ[J аrgэ) cil matlag€d
{
.entrypoiht
.,maxst'ilck е
ld.tr "CIL работает лр-енрасво! ,1'
саl1 v,aluet.Yp~ I8ystem.Wihdows, FoIrnS)
Sуstею.Windоwэ. E'arms. t ialogR9sult
1
ret
Опция Оп коан ке
~: KoIli;J~
~.
Роль peverify.exe
ПIШ создании мл::м модифmc<:lЦИИ компоновочных бдоко-в. в ROTOPbl2( ИСПОJ1Ъзу~
етсн nP0I'p8ММНЪТЙ код ClL. BceT~a целесообразно n'роверитъ. будет ЛIi скомпи.лиро
вmiНЫй. двоичный образ правильно сформирован с ТОЧRизреНfrя npaвUJ"J .NEI: ДJm
этого МD<ив:о .иеПОЛЬЗ0вать средство RОМaJЩНОЙ строки pever.ify.Eixe.
peverify НеllБРТDgr.аm.е х е
ный набор типов. Чтобы упростить рассмотрение, эти типы не будут содержать
никaRогО программного кода реализации их членов. После ТОГО как вы поймете.
как создаются пустые типы. вы сможете сосредоточить все свое внимание на про
Замечание. Строго говоря , явная ссылка на внешний компоновочный блок mscor lib .dll не яв
ляется обязательной, поскольку ilasm.exe добавит такую ссылку автоматически,
I
i
1..
Глава 15, CIL и роль д",нами~ес~ю: ~оМilO!'Iовочftых блоков 61 3
ТИВЫ. Дr,!и нашего. ИР.l<lМ.ера добавьте в определение .ЕомшшовочtlогоблОI(R J-юмер
верси:~ 1.0.0.0 с по.мРЩIl1Р дире:ктивы .ve:r (заметьте, что. все "Числовые i1деатифи
каторы в оn,редедении дolDRны раЗ.дe.1lВТьсядвоетЬЧtlем. не ТОЧКОЙ. кан в С#').
ДИР8kТМlа Оnиc.кме
• subsyst eI!\ Эта дирвkТI4ВR CIL используется ДЛЯ указSНI<IR предПО4Т14ТeJ1ЬftОГО подьз()ватель
OJCora июерфейса Ц1IЯ выполнеН~11iI ItOMnOfi080"l'fforO блока , Например •. значение
2 оэмачавт, ЧТО КОМПОНО80~\.I:ЫЙ бло!< ДОl\Ж8Н sы10J1нятьфI В рамках граф~L.\ескorо
ИН'1'ерфе~са с 1'10ддержкай форм, а зна'ЦjМИ!; Э оэма~ает консо,льнQe Прило.жеН'.1В
.паmезрасе IntertechTraining
(
.пашеарасе МуЫаmеsрасе ()
Кроме того, ПаЕ и С#, язык CIL ПОЗБоляет определить вложенное пространство
имен так.
L
Глава 15. G.IL и роль дин.а...,ичес~и)\ !(ОМПОНОВQЧ~JЫ~ блuк.ов 615
В:цобавоlC 1i а'fрибугам p.1 Jblic и extends оцредедеlЩе клаСС:-<i CIL может иметь
мпо<Sест.во доIIо.1п-rителы1х c.nецификa:rоров, эаДаЮIЦИ:II; параметры видимоеТ}I
типа.· размещения палея и '1~Д . В табл. 1'5,3 прецлагаЮТlliI описания некоторых
аrриб.утов.• которые MOryт исnолъзоваты::;n с диреК"I'$ОЙ .class.
Атрибут Описание
1
616 Часть 111. Программирование компоново"ных блоков .NET
Определение структур
Директива, class может использоваться и для определения CTS-СТРyRтурbl,
если соответствующий тип расширяет System.ValueType. Кроме того, такая ди
ректцва .class сопровождается атрибутом sealed (поскольку структура не может
быть базовой по отношению к другим типам, характеризуемым значениями). Если
вы попытаетесь сделать иначе, ilasm.exe сгенерирует ошибку компиляции.
Определение перечней
Перечни .NET [как вы помните) получаются из класса System.Enum, произво
дно го от System.ValueType [и, таким образом. тоже должны быть изолирован
ными). Чтобы оnpеделить перечень в терминах CIL, следует просто расширить
[mscorlibjSystem.Enum.
11 Перечеиlo •
. class public sealed МуЕпиrn
extends [mscorliЬ]SY8tem.Enum()
Как и для CTPyRТYP, для определения перечней имеется специальное сокраще
ние, атрибут еnит.
Замечание. Последний из фундаментальных типов данных .NET, делегат, тоже имеет специальное
представление в CIL. Подробности можно найти в главе 8.
i
L
ГЛiва 1&. CIL и роль дина-мичеоки)( ~OMnatl080!ilH~X блоков 611'
О'!~ройте окно IФwuщио{t строхи и BBemr:re следующую воманцу,
"',1,
"' .~~
1j! . . МjI'jlm8lp«8·rмwmfю
'" • ~~JЖ8,~!rUtf
'1' .• "'t'Name5JЖe..м~аи.
~ • Mt'N~ ,~\itIerI'i'8dC!1IS5
!I! 1f~--t8'."'~
'1\ ~ ~~te.МyStrtJCt
Таблица 15.4. Связь между типами базовых классов .NET и ключевыми словами С#,
а также их проекция в CIL
Тип базового КЛючевое Представление Обозначение для
класса .НЕТ слово С# CIL КоtlстаlПЫ CIL
System.SByte sbyte in1~8 11
System.Byte byte unsigned int8 О1
ROHcTpyкrOPOB - лексема. <;ctor (.кОElС'груктоР нлнссаj. Обе Э".г.и дe:кce~ CIL дошк·
БЫ СОПРОВОЩI(атьсн атрибута,\'ll<! rtspe<.:ialna111e (crreциальное имя Бозврщца~мо·
го типа) и з peci а lname, Эти атрибуты n.cЛЩIЬэуюrтся для 'ИдентмфИJ\:эцИИ специ·
альных лексем CIL. позволяюЩШI: yшиJ\альноеТOЛRование в каждом иэыке .NEТ.
Например. в С# 'КOH(,тpyI.."ТOpы не опреДeJ,ШЮТ возвраща~мый ТИП, ощщхо- в терl\olИ
пах CIL ВD3Вращощ:мым значением конструктора на самом деле будет voi d .
. cla.ss public MyE<3$,eClass
I
• fieJiij private strin.g 5t]fiI~чF'iеl-d
,field private illt32 intFielt!
Определение свойств
Свойства и Мет9ДЫ т.аюJte дмеlОТ cnециаЛЬfiые npедетanдеН:Jil.J1 в C[L Чтобы в Ha~
тем примерi' обеспеЧИТh ~ :MYB--::tSеСlаss lIоддерЖl<уomрытого свойства Т1-1еэ'triпq.
можно J,-JСПОЛЬ3(jва:гь С'.JIедУющl(Й ClL-яод (аамеп,<ft'. QrO з.п:есь Щ1Я'ГЬ ш;по;n,вуется
атрибут sресlа1паrnе).
620 Часть 111. Программирование компоновочНых блоков .NET
i!
Замечание. Указанные выше определения свойств компилироваТЬСR не будут, поскольку пока
не реализована сама логика чтения и модификации данных.
'ITO
,
J
Определение параметров членов 1
Теперь предположим, что нужно определить методы, имеющие артументы. По
сути, указание аргументов в CIL (приблизительно) соответствует аналогичной опе
рации в С#. Например, аргумент определяется с помощью указания типа данных
после имени соответствующего параметра. К тому же. как и в С#, в
чиваются возможности ввода. вывода и передачи параметров по ссылке. Также в
CIL обеспе Ii
CIL позволяется определять аргумент массива параметров (в С# это делается с по I
мощью ключевого слова params) и необяэателъные параметры (которые в С# не i
поддерживаются, но допускаются в vв .NEТ).
1
Чтобы показать пример определения параметров непосредственно в CIL, пред
положим, что нам нужно построить метод. который получает iпtЗ2 (по значению),
iпtЗ2 (по ссьmке). [mscorlibJ System.Collection.ArrayList и имеет единствен
ный выходной параметр (типа iпtЗ2). В терминах С# этот метод должен выглядеть
приблизительно так.
L
rЛ8ва 1'5. e.lL и роль АИil6Мlllческих КОМ'ПОН~8'ОЧI'IЫХ блокС. 821
Есщп сnpоеф{ровать ЗТОт МfЛ'о,ц В CIL-ROA. вы оБЕаруж:ите. \{ТО ССЫ;!IJЩ н:а "ара
~eтpы С# r>'1lI$Т обозна'Чею» змаlЮМ aмnepcaндa (&), цоt'!авленноrо в B1tЦe суффmtса
R'rИПY дa.нюiIX. соответствующему параметру (intЗ2&). дм ЗЫХОдSЬUt парам~ров
тоже исmшьзуетса суффикс &. НО, 1(роме-того. они ' обозначены мapKepQ~ CIL [outJ.
также обратите внимание 8'11 то, Ч'N) В ТОМ случае. когда пар~тр ям,нетс-и CCJ:,I-
llО~nШОМ (как тип tmзсоrНь 1System, СоНесНоns .:11.1: raY.Lis t в нашем np;u-
$е.ре) , ему npедшеО'J'вует лексема сlаЗ8 (H~ путайте с дирекrивой .cJ,assJ), '
,method pu.blic hldebys.iq !ltatic '1010 My-i"!&t~"cI (int32 inpu~ :r [:It:" ,
int:Э2' refInt,
с1.&.. trn5'oorliz;] Sys-t6rг.• CQllect ions .1\.Х' ~sy!..iat ar,
Iout] int32IoutputIn!:.,) сН Щ5n5gеd
add. зцЬ, t11ul, П038QI!1(ЮТ ltыnQJIt1я:rJo СЛQЖ8Н~8, IIIJЧ.ИТ8НИ8, ·ум~ожеjo1ие 1'1 Д8/18Ние ,1]/111' rrap
d.iv, tеЛl Э~ВЧВНI'IА (r.m 1 аОЗ.PJЩВ8Т QCTaTOK от АВJlSJ1ИR)
new a rr, ne wobj Позволяет разместить В памяти новый массив или новый объект (со
ответственно)
s t.aJ:'g 'Сохраblяет значение из верШИНbI стека в э;ргументе метода с указанны ... ИflДeJ(СОМ
з~~Ьj Колирует значение 'У1<аэанного типа Из стека в' память ПО укззанному адресу
Следует ТaIORе знап; о том, что РШШИ"'IНЫе коды оrrераций CIL при вь1II.OJ1нении
СВОИХ задач FteЯВНD удa.n.я.Ют аначe:EIИН Из стеЕа_ Например. при вы:Чи'ТаниИ ОДНОГО
'ЧИсла из другого (' noмmцыo' onерацИа
s u Ь сле.цует учитывать ТО. что прежде чем
ВБШOJmить соответствующее вычислеиие, sub Uвытолкнет" из C'r'e.IШ ДВЭ доступных
зн.ачеfiИЯ. Пос'ле ВNJ1олнев:ия опервции в creI< добавляется резуJ!Н!'ffi' 'tKaR неожи
д.aщrоl).
Директива. maxstack
При реarшзацки метода B<tuocpeдcтeeннo средствами CIL нужно помнить о Gпё
ЦИIЩ~НО:Й ДlfРСliiтиве, :которая нээ.ывается .ma-xstаtJ<. Кан следУет из ее названия,
директива .maxst.acP:: задает мaRсимаuьное число перемеRНЫХ. которые :может
.вмес.тить, CTCIt в любой J\JOM€''Н'J' :времl.'!!НИ при.-выполне:нии метода. н; счастью. ди
ре;кти:ва . fпахst ack име€'г ·зпачениё по yмШIчa1ШЮ [В}• .:которого' оказывается доста
т<эчно Д1Ш подавляющего большинства методов. создаваемых разрабо:гчmcами. Но
'J. вас также .есть воаМОЛffiОСТЬ опреде1IИ'ТЬ ·это аначение явно. ~LТО.бы при JКeЛЭlIИИ
БрJ"LНYЮ j'ШlЗ3.l'Ъ число локальвых пер€МеннЫХ II с:теке .
. rnax st_iilc k 8
11 Оnp.д.n.IIИ. '1'р8Х nOK&mo1UlX п.р....иlOUC .
. loc.l. init ([О] з tr i п q rn ySt't , [1] iпt З2 rnYln t , (2] object myObj )
11 Э.:оруах. строхи •• "РТУ.n"lOIЙ сф.к .моnи.u •.
ldзt r " C1 L те d ude ... "
11 И8Ц • • •U . т.куще:rо aK• • • KКII и сохрак.ни••:ro
11 • nохan.. иоА n.р.... кКой [О].
зtl 0С.О
Как видите, в CIL при размещении 1I0Кальиых пер еменных сначала ИСПОЛЬЗУ
етсЯ директивu . 1о с а 1 s с атрибутом При этом
8 скобках каждnн пер~меи·
i ni t .
иая свnзываетс.fl со своим ЧИСJIOВЫМ индексом (здесь это t о J, [ 1 J и [21) , Каждый
индекс идеНТИфицируется типом данных и: (неоБЯ :J8ТМЬИО) именем переменной.
После определения ло"аi1 ЪИЫХ п еременных сОотВ етствующее значение загружает·
L
Глава 15, CIL и ролЬ динами' ~еоICИХ JtQМ'ПОliO'SОЧfiЫХ 6ло~ов 625
СВ В с:те-х (1:' ПОМОЩЬЮ подходящих кодов операцИй, СМВIЩНЪ1Х. с ааI"РУЗКЙЙ) И за·
П9МИНUТСЯ s ЛЬКSЛЫlойперемt1ННОЙ (с ПОМОЩЬЮ ;цодхо.zuпцих кодов операцйЙ f1)114
со~а.неНЮ1 аначенmt),
. rt\a.xsta.c к 2
ld&~O'. О 11 Эаl'РУЗМ I а' 11 c:rel'C.
1da'1'9,1 11 ~аl'рузка 'Ь f 3 C'I'!i!1i:.
adci /I СJlрже И,11t'1 э тих 'аf{е;ч~R.Юf.
ret
11 У. . К8 118Ц8'1'CJI Сl1lа'»JRilСJUlИJ
P\lbHC.1 int Add ( 1nt е I .i nit: Ь)
j
626 LlacTb 111, Программирование компоновочных блоков ,NET
Также напомним, что при использовании любых кодов операций CIL, связан
ных с ветвлением, нужно определить метку для обозначения в программном коде
места. куда следУет перейти в случае вьrnолнения условия. С учетом этого рассмо
трите следующий (распшренный) программный код CIL, сгенерированный с помо
щью ildasm.exe (включая и метки программнога кода) .
Создание CIICars..dlJ
Первым делом С]lедует поетронтъ файл ..... сЦ 1 дин испо,щ.:зовани:Я R:лИ'ен
ТОМ. Откройте JПOбой TeнC1"OBъ.m р.едfШТОР и создайте нов:ы:й Файл *, J.lc именем
CILCa r s. i 1. Этот ОДНОМОЦVЛЬНWЙ }ЮМnОНQIЮЧНЫЙ блон будет И;СlJOльзоватъ два
внешних двоичных файла .NEl: поэтому вы можете Ыli\.чать С~QЙ файл пр.о:грам
~шога кода CILTaK
I/ Ccыn~a !ia xnscoz:lib. dll н
/I System. Windows ..FOr1US . dll
..а.sэеrnblу еХХ.егр IfIЭС.Q rl'i Ь
[
· fШЬ} н:: k.eyt oke :n = (В7 ТА 5С % 1& 34 .Еоеэ
• \ТЕ'.J; .2 : О ;0 : О
r
. a sa emt.>l у exter:n ,Б:;$ tern. wi J'. dаwз'. i;1orms
{
· p ab lick.eytoken = (В7 7'1:1 5С 56 19 34 ЕО 8 9 )
· '~e r 2: ci :0 : (j
Ita:к уЖе было cкa~HO. этот :КОМП'он(!)вочньтй блок буд~ ('рдержатъ два типа
класса. Первый тип. CILCar. одреде.л.яет два mm:я данных и дQJ\ъзовате.льский КОН
структор. JЗ:rорf,JЙ тип. CatTnfQHelpe:r. оupеД('ЛlIет еди.нс1'В~rый статичес.юШ ме
тоде именем Dis:pliiyCarlI1fo 1), ~{оторый исдользует(:ILСаг в Ш1чествеnaраметра
в:возцращает ';Oid. Оба тица ЩiXодятс.я в пространстве .имен CILCar s . В терминах
СILкласс ёlLС@т мОЩ1Jо ~аливовать 'l'ЩС.
628 Часть 111, Программирование компоновочных блоков .NET
.mв.хstасК 8
11 З_rpv.х.
n.paoro _рrуи.и,. 8 с,.х И .м.о.
11 хоисщрух,ор& e_.oaozoo м_сса.
ldarg.O 11 объе~~ 'this', а не iпtЗ2!
саН instance vOld tmsc:crHbjSystem.Object:: .ctcr()
L
Глава 10. C1L 111 роль динамически); kQМП();НОВОЧНbIX 5.1101<.08' 629
ret
Хотя здесь об.ъеМ проrpаммноro }\ода CIL ;юметяо болъще. -чем в случае реаливз
фш CILCar. на саМоМ деле вre.довсmЬi!О просТQ. Bo-перВJ:ilX_. цосколысу вы определя
ете стаl'ичесmIЙ метод. вам ае nPИД€,ТСЯ ИМеnO дело (,'0 СRР~ТОЙ объе-ктной ССЪ1ЛК"Й
[поэтому 1ЮД операц,ии lda:cg. О деЙствите.iТ,ЬНО 1щгруж,ает поступающий apryмeнт
CILCa:r).
-Метод начинается с зarpУЗRИ СТРОХi.И ("СКФРОС1'Ь { О]: '11 BCТtlC, эа НОТО'рой еле
/We'I apтyм:e!iT CILCar. Когда эти два зна"IeIOtfI онаaъmащтся- в нужном месте. затру
ЖаетCII 31Iачение поля petName й выlыветс;яя статический метод Sy,stem.Strin.g.
Fшmаt ,). чrrобы вместо эа.1Idешающих фигурных СJtоб"н получи'] ъ имя CILCar.
Тз же (!jбщая npoц(ЩУра выполняется И при обработке поля GuzrSpeec!. но еле
~e'f отметить. ЧТО эдесь исподыуетел код_ опе.РацlJИ ldarga. которая загружа
ет адрес аргумента в С.тек. Затеи вызьmается-Sу,st;.еm.Iпt32.То.Stri'D'gU. чтоБы
n:pеобраз.оваorь значение. рааме-щенное по укааЩ:IНОМУ адресу. в строковый тип.
Наконец. !{отда обе строки отформэ:тирщшнытак. ~В; требуется. выаывВоется ме
ТОД Me$sageBox: •.5how ().
Теперь вы мажет.ескомли.лпроватд свой новый файл *, dllc пам.оiЦЫo i lasrn.e-xe..
используя iQOMaндy'
Создание CILCarClient.exe
Теперь нам нужно построить простой компоновочный БЛОR .. . ехе. который дол-
жен вьmолнить С.ПедУЮщее .
• Создать тип CILCar .
• Передать этот тип статическому методу CILCarlnfo. Disp1ay (),
.modu1e CILCarC1ient.exe
/ / В'wзОВ
Display () и передач~ lIерхи~rQ ЗlJlач-.ния из ~elta.
cal 1 vold IC1l!Ca:rs]
~ILСаrs.СILСвrlпfо::Di sрlау(
с l,as.:s (С P-,-Cai:s'] CJLCa:tS,. CTLCar)
ret
ConstructorBuilder myCtorBuilder =
new ConstructorBuilder(/* ... различные аргументы ... */);
ILGenerator myCILGen = myCtorBuilder.GetILGenerator();
Метод Описание
ThrowException ()
(Jsi ngNamespace ()
Создает инструкцию для генерирования исключения
L
Глава 15. CIL ирм!> ,IIинаМИ'iески)( KOMnOt'lO.1!o!l~lbIX блощв 635
/1 Эwо'l! ~CC б?'А" соа·,цан ~ ~е.це~о.ииении
IJ с помоЩъ,lO Sузteпl. . .R.еflесtiQП .Emi.t::..
~u bl i c clas ,s Rello(iJDrld
!
:f:'x1 vat r= string t:hеМе э sаg-е-;
Ht= l lovvo.tld () {]
Н.е 11оWотlй (strlrщ $,) { theMe s $,qg~ = &.; )
рпЬ И с strinёj GetMsgj) 1 rе':Urл t1н~МеЗ'Si1-,g;e':}
pu..? lic v " id SayHel l o ()
1
Эу stеm.СОJЦ; о 16. Wri teLi r'E- ("iJp11!J5E>.T ОТ КJ'Ia-c.ca He11oW.o-rld! ") I
3иачeJlме Описание
Nеs tеdFamОRAssеш Указывает. что l<J1acc вложен в область видимости семейства или компо,
новочного блока и поэтому доступен только для методов. принадлежа
щих объединению соответствующего семейства и компоновочного блока
NestedPrivate Указывает вложенный класс с приватной областью видимости
Ne s ted Public Указывает вложенный класс с общедоступной областью еидимости
NotPublic Указывает класс , не RВЛяющийся открытым
Publ i c Указывает открЫТЫЙ класс
Sea l ed Указывает изолированный класс. j<ОТОРЫЙ не может быть расширен
3eri a l i zable Указывает класс, допускающий сериализацию
Глава 1"5, CIL И РОЛЬ динаМk'!еских КОМП .ОНРII.ОЧН/jIХ блоков· 639'
Генерирование конструкторов
мак уже УЦО.\I!ИШЩосъ выше , Д!lН оцределения RoнCтpyETopa пmа может исполь~
зоватьtя метод ТуреВцilФ~г. Й1 е finеС О Qst:ГLLсt.оr () , Однако Б Нa.tIiеЙ реализации
r«lliСтрултора Неll0СlёJJS :Э. чтобы назначить поступающий пара метр внутренней
rrр»ватной СТРOI{е. м:ы добавим CIL-KO~ в тело Iюнструтпор:а 11еnосредственн.о.
Чтобы uолуtmть. ТИП ;LLGепега t о r', вывывает(:н метод C~et 1 Н;е I."lS·ni t а r () сооrшет
ствующего 'fИlla ··ПОСТРQ~те.I'Щ", на .kOТОр'ЫЙ имее.тся ССЫЛWd (в данном случае это
ТИЦ Сons ,t l"цсtОГВ uildег).
MC'(QA, Erni1;. () класса lLGenerator отвечает за размещенйе CIL-кОда в реa.rmэа
Щ1И члена. Сам метод Ещi t () чщто :использует'ТИn Jr.JJaCcaOpCodes. который с помо
ЩЫQ полей . AOC'lynныx только для чтения, отрывает, "OC"ry1l к набору 8Одоволера
ций CIL. Например. :ОрСоае$ . Re't YK--dЗывает возврат 1Iы0ваa 1\1етоца" Qpcc.des..st f ld
в:I:.tполняет rrpисва:и:вat1J;Jeзнач:еmrя. члену- перемешюЙ. а Opcodes. Call ИCnO.1lhэует
са дJlЯ вы;,!ова методщ lB H~ с:ц.vчае это н.aнcт-ppcrop базового класса). Сучетом
сназзннorо расс:мотрит~следуЮшуЮ протраммную лdгику нонстрУ1<ТОр.а.
11 Зажору. ка yxa.a~8n.
'thi.' об~к~а 8 C~8K.
constructorIL.Emit(OpCod8 •. Ldar9_0);
11 Зажору. ха 8ХО;ЦНО1"О аР1"УМ8иorа
8 C~8K И сохраН8НИ8 8 ,m 8qFi81d.
constructorIL.Emit(OpCodes.1darg_l);
constructorIL.Emit(,OpCodes.Stf1.d, msgField); 11 ПРИС.О8НМ8 meqFi81d.
constructorI1.Emit(OpCodes.Ret); 11 Bo ••paor.
Вы. конечно, хорошо знаете. что как только для типа определяется пользова
тельский конструктор. конструктор. заданный по умолчанию, автоматически "ОТ
ключается". Чтобы переопределить конструктор. не имеющий аргументов. просто
вызовите метод DefineDefaultConstructor () типа TypeBuilder. как показано I
ниже.
j
11 ВоссorаНО8леиие ICOHC'1'pyxoropa, аа;цаиио1"О по умолчанию.
helloWorldClass.Defin8D8faultConstructor(MethodAttributes.Public); 1
{,
Следующий вызов порождает стандартный СIL-RОД для определения ROHCTPYК-
тора. заданного по умолчанию .
. met hod public hidebysig specialname rtspecialname
instance void .ctor() cil managed
. maxstack 1
ldarg.O
call ins tance vo id [m.scorlibJ System. Obj ect: : . ctor ()
ret
Резюме
в этой .главе upeДJIRГae'],'c,ft кр~ткий ьрзор B03-МОЖНОС'I-е'Й сщrтаксиса и (.:еман
тики <i:JL. S ОТЛFlчие от управляемых H3Ь1КDB высшето уровня. таких как, нanри
.мер., С#, в CIL не цростооцредел:яется набор ЮlЮчевых СЛОВ. нЬ и ДИРeJtтивы (для
опреД~eJ-ЩЯ: С'l"руктуры liQМIIt!Новочвого блока и его тиncлi), а;]риБУ'l,ы (угочннющие
,JЩрa:ttтерuстщщ СОО'l'ветствующей дирекТЮ!Ы) и Eoды операций (:используемые д.!ш
рещmзации члеIШВ типов). Еыл T~~ рас('МОТРен хом':!:IпJIя'toр ClL (ilasm.-exe}.
вы узыади О :гам, щш и~elЩ'ТЬ оод"t'ржимое ЮJМпоновочнего блока .NEТ, нerюcред
СТ'~ЩilЩ Д3мещ:rя ero програм:мньiй IiOA CIL. 11 рассмотре.ли осн.овные этапы про
десса noс:rpоения -КОМПQНОВОЧНОГО БЛiJЮi .NEТ с по:моtцью CIL.
Вторая UОЛОВ.f.IfЦt Г.lДiВЫ бы.ilа посвящена оБСу-.tRдени:ю np tiC: тpaнCTBa имен
s.y steIТL.~ ef le.ctior]J Emit , Используя СОDТВетствующие 'ГИlIbl. БЫ можете С03-
Дa.Iщть КОМЦОF,lрщ)чные блоки .NET в ШIМЯТИ динамически. при желании мо,ж-
1-10' ТЗJ.'Щ\е сол--ра:нить GОЗДанньrй в памяти образ в фиэигчес:ком файле на дис-ке.
М~:iOГи~ 'ТИПЫ Sy,s.tem .Re f l Bct а. оп. Emi t авто:матич.еСКИ генерируют ПОДJ!:Qдящие
ДI!rрекгиры и атрибут:ы. CIL, Используя другие свнэamrые сшши тИIlliL таки~ как
Co,nstrt.,fctorBuilder, Type-Bu:i ldeT ит.д. Тип ILGe:r::eratill: мо~еТИEIlоЛЪЗ0ва:1ЪСЯ
A1Цl доб<ЦiJIеJfl'lЯ Н:~QБХQД:ИМЫХ .кодi!lвалерациИ CJL в члены типа. И хотя qществует
цеЛЫ}1 ряд всцомuга'ГеJIЬ~ ТИПОВ. ПРИЗБанНых УПРОСТИТЬ ПРDцесс создания про
.грамм при ИСПQJiЮОВании :КОДОВ операций сп., ДlJЯ уtmenпюrо СО3,цЗния динамиче
С1КИХ :НОМПDНОВОЧl-iЫX блоков вам rrtmaд0б:ится хорОшее nонимaiil:ие язьша CI'L.
ЧАСТЬ IV
п рограммирование
с помощью
библиотек .NET
в этой части'...
П .
ри ссщц2iRИИ поJiШЩf:IiНЪ1iX цpиii~ Иctafю!Ш'"J'~IЫЩ щщща ~~Ii3М"~1'Ъ
СOX]!lанешtВ, EШI.}1QРМa.rnц:r 'МfflЩIy сea:яu~ ДQ.cтупа nCШЫiЮЩIТf'.rrа, В Э1'~)Й rJЩ
.ве:рwсмз.триваеТС,!;I ЦeJa.m p.a;n, :вQЦpOC,O:н, cВ;!iЗв)'J1IIbl!o.2 € Рf1,ащ1J3~' 1}'ВO~~ щu.вщда
11 .NEт. ПеРD"ОЙ ffiш:reй ~~ч.ей будет I.itt~ ба~о~ l'1:I;rIСЩ 'Qцрt:.Щ~..дI:Щ.fЩJE
:!l прос'JJР2I:1CТве ШIttН В'iStе'I1l .IQ,:и J\1I:oИJ~ ТОГО, 'iШ.Jt РРШ'Р~ ('r4{('~-
1оШ можв.а 1!3!1reНl\Й'1i РООQ'ШЙ ШJi1'aJior -~ с ГрУК'1:00 ф.iйпов М<ШlЩ'Ibl'_ Цfl/me 131'01'1,\1 щ.r
paCtJ>MМJ!IFIМ Р:il3ЛВ:ЧНЫе, IlФзмйtЖнёt'т'R "n'i!ПИЯ Н; 1fШlИСИ ~'BЦъr~ 'щ! фa:iЦr~'W С ~и:м
JЮЛЫ:{QЙ. доо-wчnо:Й н ~ ОРJ'аиизацшей'. й T~ ffi3 ЩiмR'J'J~.
Неабстрактный тип
Описание
lUIacca ввода-вывода
Bina r yRe ade r Позволяют сохранять и читать примитивные типы данных (целые , логи
BinaryWriter ческие , строковые и другие), как двоичные значения
Buffere dStream Обеспечивает временное хранилище для потока байтов, которые мож
но будет направить в другое хранилище позже
Drive l nfo Этот тип (появившийся В . NEТ 2.0) предлагает подробную информацию
о дисках, установленных на мащине
L
Глава '16, Г!ростр-анатво j.1МЩ1 System .1O 649
Object
Di recta.ry
, File
Р} lеsу,s·tе,шLrnfо'
Dir~ct'0ryJij fo
liastf1J:i teTime Чищет или устанавливает время последнего оеанса эatlиси 'в текущий файn
/АЛИ Каталог
Natne Дл~ фaiiл0В получает имя файла . Для каталогов П"ОЛY'ffi.5Т ИМЯ последнего
К"в:галога в иерархии, если Т,акая иерархия существует. Иначе П(fЛУчает!о1МЯ
·к;атаЛDг'а
1
650 Часть IV. Программирование с помощью библиотек .NET
тип Fi leSys temI nfo определяет также метод Ое lete (). Этот метод реализу
ется прОИЗВОДными типами для удаления данного файла или каталога с жестко \
I
го диска. Кроме того, перед получением информации атрибута может вызываться
Refresh (), чтобы гарантировать то, что информация о текущем файле (или ката
логе) не будет устаревшей.
Члены Описание
GetFiles ()
щего каталога
I
l
["пава 16. Пространстtlо имеf! Sуstеm.Ю 651
1/ flршur81Ci1 Х lleiсуще.с:.!1J!.yuцeиу 1C&!Z!&Jtorv с ПОC3Jед~ ero соз.ца _ _ .
birecturyIl'1fo· dir3 =ne ... Di.тесtо:r;уlпfо.(@"С: '\Wi:ndQws\Тееtiпg"):
di rЗ. Create () ;
/I ~фop!!fa~, о Jt8'1'UIo:rre.
Соns~,)lе .• W-:titеLiriе (""!О,'Н,. Информация о ~ата:ltоге ~""'**"},;
C,or..sQle. Wri t eLine ( "Пс:'1ГНО~ им.л: {О J .;, cti.r. FуllИ.aJt\е '}, ;
"y~ .t-1
"<-ОПЗ'9 1е _,.,. .
",~~ne """"". 101 " , .d 1' r. N ате)"
("rA."_. ' .
C01'lso1e. Wr i teLln.e (" РодW-rель: f О} ;" di:r. Pare!').t) ;
СCiП$ . оl~.W,:r i tеLiле('·Создан~ {О} 1', dir.Сrеаtiолt!:imе);
С (;ns оlе.W'r'itеLiпе("А'I'р'и.бу\ш'!: {О}", dir.Attrib!Jte,s ');
ConsOle. W.ri teblne (i'КQРRевой K3.T.aJ1o.;г~ [О I "'. dir. Root) ;
CoI'tsole. 'W;ritеLiпе ("* * .. ** *" ....... "'*.*'** ~.* * '" *......... *** .. **. ,* . \п") ;
'ПереЧ'ень FileAttributes
Свойство AttLibiJtes, .Предостanле,EJ:FJое оt)ъеJ:t'I'OМ П;L-еS}''S1:е.mlлfо. обеспечива
ет получеI-ше раЗJIllЧНОЙ щrформaщm о тенущем хатапоге nл:и файле, и вся она со
держится Б перечнеFil еllttгiЬutеs, Имена полей' этого церечня rоворят сами за
себя, но неНO'rорые менее очевидные имена эдесь сопровощдa:IO'I"CЯ коммeн:raр:иями
(подроб'нОС'ГЕ ВЫ ищете в докумеmaдии .NEТ F'ra:mew(Jrk 2.0 SDK).
1
..,....
,
I
class Program
{
static void Main(string[] args)
[
Console.WriteLine("***** Забавы с Oirectory(Info) *****\п");
DirectoryInfo dir = new OirectoryInfo(@"C:\Windows");
// С~оль~о их всего?
Сопsоlе.WritеLiпе("НаЙдено (О) файлов *.Ьmр\п",
bitmapFiles.Length):
Гл&ва 16. Прос.транство И'-1&Н System.IO 653
/I ВJ.!aO'Д юtформаQJm О ф.мах.
foreach (File'Iofo f ;1.n Ьitmа.рFilез)
{
COn,501 е. )oVri teti!!'e (" *** ... "'*" '" "'* .. * ... *';' .. .......... .. ,. ** ...... \11" ) ;
.Сопsоlе_ Wr1t ,eL.lne .( "Иv..я: {О} ", f. NаПlе -) ;
C.onsole. Write:L:Ln6 ('i~аЗ)IJе:р: {О} ", f. L:engt!1) I
Console.W'rit;e1ine,{"\,:-оздан: {О'] ", f.СrеаtiQпТiJ:rlе)i
Console .Wr i t:еL'iп-е (" АТР11буты:: 10} ", -f. At tr ibi:ltes) ;
СОП501е.w~itеLiпеJп .... ~**** .. *~ ... *r·***~,,,,,,,,~ ~~* ·\пl,);
clp.$·s, P;rogram
~
static void Maih (st:r:J:ng!] аrgэ')
!
со:nsаl€.-W'rit.еLinе (n .......... заб.ав~ t; DireC'tot'Y (1пfо) **H~\()';. ) I
Directorylnfo Ф,r = TLew OirectQryIrofo (@"е: \Wiлdоw.s··!) ;
654 Часть IV. Программирование с помощью библиотек .NET
d = dicCreateSubdirectory (@"MyBar\MyQaaz");
Сопsоlе.WritеLiпе("Создан: {О) ", d.FullName);
L
cl~$., P;rpgrwn
-{
6,иtiп "lO"id Nain 'l st;ring t1 ~!,g$'}
1
11 СmIOQ!{ ДI4;~()}t ,1!i]UIRQX'O '~QМПЬ~а •
.s±1: ".'1'1g t~ ":iriv.~'S, = Dii. rS .сt.а>.:гу ,'[jeti€l(J::' сдl D:r i.чеэ. С). I
CQti~IO.l Е • Wcrl t€!'L,i!,e ( ·" ifi()"i'· JillGtшИ, диС1':И:.: W'~ ;.
Console.ReadLine()i
'{лен Описание
Appt;ndText (,) Создает Т1I1H StrearnWriter (буде'" ,оПIo1е.ан МЗ)I{&) ДI1~ добаsлеf.l\о1Я тек
став файл
СоруТо () J(dпирует существyiOЩИЙ файл в I<IОВЫЙ файл
Crea,t eText.. (') Создает тип StrearnWri tet, k!)ТОРЫЙ записывает новый текстовый, файл
Delete (J Удам'вт файл. к которому приs~заж экземr:щяр filelnfo
Dire-ctory ПалуЧQет э~мпmф KaTВJlOгa Р'l)Дитеhя
Метод Filelnfo.CreateO
\
'! Первая воЗМожность созданй.fl деС.крип>гора файла обеспечивается Meтo.n:oM
р): le Info.Creat:e О.
Метод Filelnfo.OpenO
Метод Fileln fо.Орел () можно использовать для того. чтобы открывать сущест·
вующие файлыI и создавать новые с более точными характеристиками. чем при ис
пользовании Filelnfo.Create (). в результате вызова Ореп () возврarцается объект
FileStream. Рассмотрите следующий пример.
J 'Wri teOnlyS,tream.Close!);
660 Часть IV. Программирование с помощыо библиотек .NET
Метод Filelnfo.OpenText()
Другим членом типа Filelnfo, связанным с открытием файлов, является
OpenText (). В отличие от Create (), Ореп (), ОрепRеаd (} и OpenWrite (), метод
OpenText () возвращает экземпляр тиnа. StreamReader, а не типа FileStream.
static void Main(string[] args)
{
sreader.Close();
swriterAppend.Close();
L
Гла;зэ 16. Пространство ИМ~I'I Srstem.1O '661
Filеstrеаm'ОКазываются ВЗaIOЮзnменяемъtмn. T~. D-JШЖДОМИ& upедp.rд;ущщ щrщ
Меров вместо Fil&Stream можно использовать тип Fi 1е.
static vC>-l.d Ma'in (string[] ,args)
(
j I Попучеиие О'б'W!JtТ& FileSqecn с DОМCiЩЪJ) Fil~. Crea te () .
Fi1 $S tre<;\m f s = Е'Не. c::reate (@ nC,; \T~st:. da t',·:) ;
f:s. • cl o..se ( ) i
/ I ПQ;nучеюte 06'ИJC'1:а. FileStream с ПОIllOЩЫD File , Ореn () .
FilеStrеdП1 [э2 = File.Opel'! (@"С; \1'e'8,t 2 .det n I
filеН!йdе.О'реГ!ОrСrеаtе,
fileAcDe-3s·.RеаdWri te., Fi1eSr.a:rce. Nc:ne) i
fзl . Clc:se О i
11 По~евие объеJCша.Filеstre_ с .1I,QСoryпои mom..Jil:O Д;n.SI 'И'еИИ5l:.
FileStream r~QdOnlyS.trepm = File.Open.Rea.-d.('@"'ТеstJ _ . dаt" !;!;
r,eadOnJ у,S·lIеа.щ. С 1 ОВ'е (J ;
/J По;nyчеме O~X'1!a, Fl.lеstrеш с доступом ''I'onьxo ДШI запиеи.
i"ileSirea:m writeOnlyStream = FH е .. ОреПWJ:i t,e \@"Test4 . dat n ) :
Метод
~eadlUJ.ByteJ3 О '{).ткрьщает ук~за.н~,ы~ файл, ВОЗВр'~щает jЦВОИЧНЫе. дa!1fJble в ВИД!'! мас
cl'ffia байтов, а затемзакрь,взет фаил
~eac1'AILLlilf?S () Оl1фывэет у~азанный файл, возвращает с~маольные ДEll"lliые в виде
массива стро'К, а затем закрывает файл
P-еа,dAllТех t 'o Oткpt,'вэеr указанный файл, возвращает символьНые дIlliHЫ.e в эиде'
Sу,s,tеm.Бtr:iлg, а Щlтем закрывает файл
Wr:i teAllТe.xt. (.) ОТlф.!II.Вает ук:а=,анный файл , зап'исываеi СИМ81JJ1ыtые даt:JНf.,те, а затем
заl\:рывает ф1J,ЙЛ
662 Часть IV. ПрограммироваНl1е с ПОМОЩЬЮ библиотек .NET
При использовании зтих новых методов типа File для чтения и записи пакетов
данных потребуется всего несколько строк программноro кода. Более того. каждый
из указанных новых "шенов автоматически закрывает соответствующий дескрип
тор файла. например:
class Program
{
static void Маiп(striпg[] args)
{
string[J rnyTasks = !
"Прочистить сток в ванной" I
Очевидно. когда вы хотите быстро получить деСIq>ИПТОр файла. ТlШ File из·
бавит вас от необходимости ввода нескольких лишних строк. Однако преимyIЦе
ство предварительного создания объеI,та Fi1eInfo заключается в том. что тогда
вы получаете возможность исследовать соответствующий файл с помощью ч.пенов
абстрактного базового класса Fi 1eSystemInfo.
static void Main(string[] args)
{
// Вывод информации о файле boot. ini
// с Dоcnе.цуации отхрытиеи .цоступа mолысо ,цлк чтеНМR.
Fi 1е1 n Ео bootFi1e = new Fi1e Info (@"е: \boot. iпi") ;
eonsole.WriteLine(bootFile.CreationTime);
Сопsо1е.WritеLiпе(ЬооtFilе.LаstАссеssТimе) ;
FileStream rеаdОпlуStrеаm = bootFile.OpenRead();
rеаdОпlу8trеаrn.еlоsе() ;
.
L
Глава 16. Про.страНСТВD имен system.1O 663,
АбстранТВЬ!Й КJlace S~_stem. IO.stTearn определяет ряд членов, обеспечивающих
поддеWIP'Y q.шxррнноro и i:!СЙНХfЮННОГОl!Заимо;цей:ствив с ЕюситмемдafIНЫX (ска
жеы. с файдом: ИДИ обл~тыо памяти). На рис, ] 6.6 пав:азано llесКШlЪКО потомков
типа StrеЩТ!.
Strea1t1,
FJleStream
ыleтoT-yBиы.m.
I EufferedStream
Рис. 16.,6. Типы, ГТРОИЭВОДНЫВОТ StJreq.m
3a...e-"8НJ11e.
Сл&дуе, знать, ЧТО ПО~lятие потркэ примеНI1МD не ТОЛЬКО 1( файлам ~1'ЛИ оБЛ;;JСТИ nSM>I-
ТИ . Без сомнения, бlilбл'и,отеки .NEТ ot5есПeчmJают t:lотоковl;Iй доt)туп' к сетям И ДРУГ1-1М С8ЯЗВI'r
I:IblМ С по1'ОkaМИ абстракЦиям.
Чпенw Описаliие
C&nRea'd Qоределяет; поддерживает ЛИ текущий поток "тение , 'поиск и/или запись
J;~I'1'Se~k
CanWrite
Close () Завершает текущиЙ nGТOK н' освобождает все свя,занНые с тщщt.:11У1 Т1ОТОКО/>А'
ресурсы (например, coквl'ы и дескриmоры фаИ~lOа)
Flu.sh () ОБНОВЛЯElТСВЯЗаннOIИ иСтО'lНИК ДЗНrlbIX ,1OIJ1l.II хрэмwrli!Ще в соответСТllИИ с Л:i
~ЩИМ СОСТОRнием буфер<\. а затем О"IИЩает буфер. Если ПОТ0К не реfИ'lизует
буфер" ЭТGт М(ПОД Не Дед'ает НИ'!I;\ГО
Lengt~ Возвращает ДflиflУ ПО'tOка в байтах
Position Определяет позицию в теl(yщем 'потоке
ReadO Читает ПОС118дрвателЬfЮСТЬ байтов (или один' байт) из текущего поток,а и СДЕИ
ReadI3yj:eO п~ет ук~тещ, ПО3ИЦIIIИ В {;оответствии со С'IитаННЫhl '1ИС110М бай'mв
Работа с FileStream
Класс FileStream обеспечивает реализацию абстрактных членов Stream в
виде, подходящем ДЛЯ файловых потоков. Это довольно примитивный поток- он
может читать или записывать только один байт или массив байтов. На самом деле
необходимость непосредственного взаимодействия с членами типа FileStream
возникает очень редко. Вы чаще будете использовать различные уnаковщulCU тю·
moКОВ, которые упрощают работу с текстовыми данными или типами .NEТ: Однако
для примера давайте позкспериментируем со средствами синхронного чтения/за
писи типа FileStream.
Предположим, что мы создали новое консольное приложение FileStreamApp.
Нашей целью является запись простого текстового сообщения в новый файл с
именем myMessage .dat. Но IIОСКОЛЬКУ FileStream может воздействовать только
на отдельные байты, требуется перевести тип System.String в соответствующий
массив байтов. к счастью, в пространстве имен System.Text определяется тип
Encoding, предлагающий члены, которые выполняют кодирование и деКОдирова·
ние строк и массивов байтов (д.ня подробного описания типа Encoding обратитесь
к документации .NEТ Framework 2.0 SDK).
После вьmолнения кодирования массив байтов пере водится в файл с помощью
метода FileStream.Write(). Чтобы прочитать байты обратно в память, необхо·
димо переустановить внутренний указатель позиции потока (с помощью свойства
FQsition) и вызвать метод ReadByte (). Наконец, массив байтов и деКОдиРован
ная строка выводятся на консоль . Вот полный текст соответствующего метода
Main ().
// Не аабу~ьте 'использова~ъ' System.Text.
static void Main(string[) args)
(
Console.WriteLine("***** Забавы с FileStreams *****\n");
/ / Получение объеltТа FileStream.
FileStream fStream =
File.Open(@"C:\myMessage.dat", FileMode.Create);
/ / КОДИРО!lание С'.1'РОl'tИ в !lи.це масс_а байтО8.
string msg = "Привет!";
byte[] msgAsByteArray = Encoding.DefaUlt.GetBytes(msg);
L
Глааа 16. ПРQСТРЭНС:ТВО и~ен SY$tem.1O 665
1/ Вlaoд lЦехО~Q.&1IИ.0%'О сообщение.
С:оnзоl е
. W'rit€ (П \:nДе!<QдироваЩ'Iье с;ообщеl;iие ~ ");
Console_ Wri t,eLll'1'e (Епсоding. Default • G€tstring (bytes.FromFile) I ;
I/ ~&аеPJllевиie по~аll:&.
f,s,tream.Close(J ;
ХОТЯ в этом прцм, ере файл данн:ы:ми не заполняется, уже здеоь становится
очевидныM rna.внъ.Щ :цедостатoR работы СТИПQМ FilеS:tгеаm,: приходится воздей
СТJIо&этъ непосредственно на отделъ:в:ы.е байты. Дрyrие ТИПЫ. яв:тшющиеся произ
III;1ДНblМИ <>Т S'trea.m, работают анало:г.ИЧН'о. Например. чтобы записать nоследова
-reлъность байтов в 3~ область.пa:мJпИ, :МOНm"o исnoльзоватъ MemoryStream.
Точно Так же, чтобы переда'FЪ массив байтов по сетп, вы можете исПОЛЬЗовать тип
:Networ kS,t ream.
J:t счщ:тью. цространство имен Sy.stem.l.0 предлагает цеirый ряд типов ~чтеНия"
_я, ·зади~·. "ЦНRЩIсулирyIbщих особеIlНОСТИ работы с типами. ПРОИЗБОДНЫМI1 от
Stream..
--10... .
т
666 Часть IV, Программирование с помощью библиотек ,NET
I
Object
TextReader
StreamReader
StringReader
TextWriter
StreamWriter
--1 Stringwriter
Рис. 16.7. Читатели и писатели
Член Описание
Flush () Очищает все буферы текущего записывающего объекта с тем, чтобы все дан
ные буфера были записаны на соответствующее устройство, но не закрывает
сам записывающий объект
NewLine Указывает константу обрыва строки для производного класса записывающего
объекта, По умолчанию признаком обрыва строки является возврат каретки с
переходом на новую строку (\т\п)
Write () Записывает строку в текстовый поток без добавления константы обрыва строки
Wri teLine () Записывает строку в текстовый поток с добавлением константы обрыва строки
Замечание. Последние два из указанных в таблице членов класса TextWriter, вероятно, по
кажутся вам знакомыми, Если вы помните, у типа System.Console есть члены Write ()
и Wr i t еL i nе (), записывающие текстовые данные в устройство стандартного вывода,
На самом деле свойство Console. Iп является упаковкой ДЛЯ TextWri ter, а Свойство
Console.Qut - ДЛЯ TextReader,
!
l
L
[Л3iа 16. npocrpaflcTBo име~ISуstеm.10661
Член Описание
I
1
670 Часть IV. Программирование с помощью библиотек .NEТ
r
/ / Создание StringWriter и B:WВOД сиивоnъlWX дaНIWX в П8.llJR'Ъ.
StringWriter strWriter = new StгiлgWгitег();
strReader.Close() ;
Член Описание
член Опмоаl'lие
/I Звшroь даяиых.
Ь"" .Wri t-e (aDoubl е ) ;
bw.Write (аnfлt-j i
bw. Write '(а Cha.rArr а1 ) ;
bw .'Clo$e () ;
672 Часть IV. Программирование с помощью бибЛl-\отек .NEТ
r
I
Обратите внимание на то. что объект FileStream. возвращенный из Filelnfo. t
OpenWrite (), передается конструктору типа BinaryWriter. С помощью такого под- f
хода очень просто выполнить "расслоение" потон:а перед записью данных. Следует
осознавать, что конструктор BinaryWriter способен принять любой тип. произ
водный от Stream (например. FileStream. MemoryStream или BufferedStream).
Поэтому. если нужно записать двоичные данные, например. в память, просто ука
Жите подходящий объект MemoryStream.
для чтения данных из файла BinFile.dat тип BinaryReader предлагает мно
жество опций. Ниже мы используем PeekChar (), чтобы выяснить, имеет ли ПОТОI<
еще данные, и в том случае, когда он их имеет, использовать ReadByte () для по
лучения значения. Обратите внимание на то, что байты форматируются в шест
надцатеричном виде и между ними вставляются семь пробелов.
1/ ЧlJ1еиие данных
s виде 11 сырых" бaЙ'l'оз.
BinaryReader br = леw BinaryReader(f.OpenRead());
int tешр = О;
while (br.PeekChar() != -1)
{
Console.Write("{0,7:x)" br.ReadВyte());
i f (+нетр == 4)
/I Запись хаждых
4 бaЙ'l'О:В :в :виде нозой с'l!pо!tи.
Console.WriteLine() ;
temp = О;
Console.WriteLine() ;
catch(ArgumentException ех) {
Console.WriteLine(ex.Message);
return;
I
j
l
Рис. 16.10. Н~БЛЮАение за текстовыми ф8Мам~J
Асинхро.нныЙфаЙловыЙ ВВОД"'ВЫВОД
Взаверщесще вщnего об;:Jора цр.остранства имен SystE:IТ1.IO д~айте ВЫ:nСЩЩ\d,
:КаЕ осут.цеств.цяетqr асивхроннuе вэа:имодействие с ТИШIМЙ File5treq:m. ОДИН из
ва:риантов поддер:щки аЦllIХронного взаимодействия в .NEТ вы уже видели np:и
I
ра(;смотр~щ~н l\>IНОГОD.О'ГОЧНЫХ прюIOЖенйЙ СМ. м,аву 14). Ввиду Toro, что BBOД-B~
ВОД может ;mнш.ЩТh lIrщотовремени. все nmы. производнъtе 01' SJ5'tern.I(j_Stre~m.
наследуют мво:жество методов, раэрemЯ10ЩИХ асинхронную обработку ДCЩfЦ,PC.!\щt
и следует ожида'IP. дЩ методы работают.в С'ВНЭ1~е с пшом IАsу:r~С"Rеs11lt-,
Резюме
Эта глава начинается с рассмотрения типов Direct o r y (I nfo ) и Fi l e (Info)
(а также нескольких но.вых. членов типа File, появившихея в , NEТ 2.0). Вы узнали
о том, что эти классы пазволяют работать с физичеСliИМИ файлами иди каталога
ми на жестком диске. Затем был рассмотрен ряд типов (в частности, FileS t сеат),
полученных из абстрактного класса Strearn. ПОСRОЛЬКУ типы. праизводные от
Stream, работают с патоком "сырых" байтов, пространство имен System.l0 предла
гает множество типов ввада-вывода (StreamWriter, St ri[1gWriter, Bin.a ryWr iter
и т.п.), упрощающих процесс.
В працессе обсуждения был также рассмотрен новый тип .NEТ 2.0 DriveType,
вы узнали о том, как контролиравать файлы с помощью типа FileSysternWatc her
и как взаимодействовать с потоками в асинхронном режиме .
I
l
ГЛАВА 17'
Сериализация
объектов
1
678 Часть IV. Программирование с помощыо библиотек .NET
Наконец. следует понимать. что объектный граф можно сохранить в любом про
извоДНом от System. IO . Stream типе. В предыдущем примере объект UserPrefs со
хранялся в локальном файле с помощью типа FileStream. Но если бы требовалось
сохранить объект в памяти, следовало бы использовать тип MemoryStream. Это не
обходимо для того, чтобы последовательность данных корректно представляла со
стояния объектов соответствующего графа.
Глава 17, СериализаФ1R объеJCТОВ 619
Radie
ПРОВJШ.lDпирооав эту формулу. Щ>I с;нова увидите. --.:по объе'КТ 3 .сСеН) имеет за
в;mлIМОСТЬ в О'FНотеюm объе;rста _2 (R.a'd ic). Объект 2 (На dio) в:влнется ·индивид,v
aI1ИС'ТfJМ". которому ншtrо не требуетсs;i. Нан:ошщ. оБЪе!(Т 1 [,Jame5B~:mdOar) имеет
завИСИМОСТh в OТ}IошеНItи КaJI: (!)QЪC;Rl1il З,так и объе:кта 2 . В любом случае. ког
да выоJшяетсfl сеРИЗ)1изаuця или реI<ОНОТРУКЦИJI Э'l<эеМПJшра Jа.шеsВоn-dсат.
680 Часть IV, Программирование с помощью библиотек .NET
объектный граф дает гарантию того. что ТШIЫ Radio и ear тоже будут участвовать
в процессе.
[Serializable]
public class JamesBondCar еау
(
public Ьо о1 canF1y ;
public bool canS ubmerge;
Следует знать о том. что атрибут [Serlal izable] не наследуется. Таким обра
зом, если вы получаете класс из типа. обозначенного атрибутом [Seriali zable ] ,
дочерний класс тоже следует обозначить атрибутом [Serializable). иначе он l
при сериализации сохраняться не будет. На самом деле все объекты в объект- t
ном графе должны обозначаться атрибутом [Serializable]. При попытке с ПО- j
j
L
МО)]ц'Ю в,iпаr' уF'оt"щ:зttеr или Saa.pFor,rnatter выполнит.!,. сериализацию объеь."Та.
ке !1QДJreжащегосери'WП'tЗа.Ции, в среде ВЪ1полне»ия l'енерируеТС~ nсклю~,е.ние
SеriаJ.i2аtiОо.ЕхсерЦс~n.
ные, дoc'JYIIНЪТe через открытые свойства. Также для проe>rоТ'ы не было опредедeнri'
юma.JGШ доцъэователыжих 1:W1ICТpyкropoв для этих THUOt'l. DooroMY все Щ :ПОJJ,Я да;н
паток. Ответ здесь завис.ит от МНОГОГО. Есди -В:ы сохра,нцете оБЪ~RТ ~ помощью
Вin~l-уFоrmаttеЕ, то определения не имеют абсолютно НИRaRОГО зн~чеНИJ!. ЭтQТ
ти;n ПР~ЩfазШiЧен д;nя. оохране,ния всех npеДНЭЭН8'lewJbl.'С ДЛЯ' серщщиэации попей
1'ИПа, н~зав:ис:нмо 0'1' то:го. ИВЛflЮТСЯ ЛИ они общими ПОJJЯ~:И, цриватными поля
МI11 :и;ди приnатными полями, достym-lымй черftЗсвойства типа. Одщuщ Ситуаци8
Оlщ~~ся ,соверnrенн() ИНОЙ. если Вы ИСПО.JJ:bэуете тип XmlSerializer или тип
DоарFфпn,а-t. t 'e I'. эти ,mпы :в.ьптолнmoт сери:алиэацию nш,-.,ысо 6T~PЫTЬ1X ПОлей дан
НЩ ~ прйватныХ данных, доступных через OTJ{P;blTt>I(' свойства.
напомним, однако. что если имеlOТСЯ ПОЛЯ ДЩ-nIых., КО'горые ~Ы не хотите со
xpaI-lЯТЬ в объектном графе. -вы может.е селективно ИCnОЛЬЗЩЩ1Ъ Д.JIЯ них атриfiyF
[NQлS.е:rlаlizеd]. кан это сделано со CТPOКOBblN( щmем типа R,a;Ho.
• Хm l SеriаЦzеr
1
682 Часть IV. Программирование с помощью библиотек .NET
L
Глава 17, Сер~аnизация об:ъектов683
I
--L
684 Часть IV. Программирование с ПОМОЩЬЮ библиотек .NEТ
Сериализация объектов
с помощью BinaryFormatter
Чтобы по казать, как сохранить экземпляр James80ndCar в физическом файле,
давайте используем тип BinaryFormatter. Подчеркнем снова, что двумя ключевы
ми методами типа BinaryFormatter являются Seria1ize () и Deserialize () .
• Serialize (). Сохраняет объектный граф в указанном потоке в виде последо
вательности байтов.
using System.Runtime.Serialization.Formatters.Binary!
using System.IO;
// Создание
JamesBondCar и установка данных состояния.
JaroеsБопdСаrjbc = new JаmеsВопdСаr () ;
jbc.canF1y = true;
jbc.canSubmerge = Еа1зе;
jЬс.thеRаdiо.stаtiопРrеsеtз = new double[] (89.3, 105.1, 97.11;
jbc.theRadio.basTweeters = true;
L
[лава 1"7, Сериали~аЦl"!I объектов 685
... х
ly ,L
h=R~~10,~s~~tcaB
е;ЬК .' • _ SiJllpJ.~
SerJ."Hu.tion _'R"
d,io., " 1. 1' " , •• , .
"' ,~ple
~;а:-l~liZ<l ~"i.onR~
dic " .. . has"!:"ee.t
e~ na$Subl;.Т""f,er
-s , st'аtici1lPreoi",tэ
, . '
1
686 Часть IV. Программирование с помощью библиотек .NET
Сериапизация объектов
с помощью SoapFormatter
Следующим вариантом является тип SоарFоrrпаttе:r:. тип SоарFо:r:шаttеr со
храняет объектный граф в сообщении SOAP (S1mple Object Access Protocol - про
стой протокол доступа к объектам). что делает этот вариант форматирования пре
красным выбором при передаче объектов средствами удаленного взаимодействия
по протоколу НТIP. Если вы не знакомы со спецификациями БОАР. не воЛНУЙтесь.
В сущности. SOM определяет стандартный процесс. с помощью которого можно
вызывать методы не зависящим от платформы и ОС способом (мы рассмотрим
SOAP чуть более подробно в последней главе зтой книги при обсуждении Web-cep-
висов XМ:L).
в предположении о том, что вы установили ссылку на компоновочный блок
System.Runtime.Serialization.Fo:r:matters.Soap.dll. можно реализовать со
хранение и восстановление
JamesBondCar в формате сообщения SOAP с помощью
замены BinaryFormatter на SoapFormatter. Рассмотрите следующий программ
ный код, который выполняет сериализацию объекта в локальный файл с именем
CarData.soap. [
using System.Runtime.Se:r:ializati on .Formatters.Soap;
ь
Глава 17, СеркалкэаЦИII объеп.QВ 687
<has SubWoo f er's:> falве<,,!hаSSUЬWО0 f ers >
< s,tationP1;-msеts href=-"#re Е-4" 1>
</8.1 : Radio>
<SОАР-ЕЩ: 'Array id=·".ref'-4" 8ОдР-ЕNС ~ arrCly1:ype="xsti:double [3') ">
< item>Э9.З</itеm>
< i -lеm>l О 5.1</ item>
< i t-em·>'97 .1 </ i t .em>
":'/SOAP-ЕNС:Аrrар
</ S'OAP-_ENV: Bodj>
<!SOAP-ENV;ЕJJvеlоре>
Таблица 17.1. Атрибуты пространства имен System. Xml . Serializa tion, связанные
с сериализацией объектов
Атрибут Описание
<canFly>true</canFly>
<сапSub1'tle:tqе>fаl.е</сanSubmех-gе>
.; / ~1amesB~ndCa.r>
Ест! вы хотите указать пользовательское пространство имен XМL. соответству
ющее 'LlamesBondCar. икодироватьзна"'lенпя салFlу псапSuЬmеrgе в виде XМL~
атрибутов. это МQЖИОСД~.Il:ать с ПОМОЩЬЮ изменения (.Jпред~~нил ,JаIilез.1i30пdС:::аJr в
С# следуюЩИМ образом.
[&erializa:ble,
xmlRQot {Namesp&Cle =
"bttp: Ilwww. intertJilCl~tr&in,i.nq. СОЩ"} J
public шав,а ,"ra."'11,esl!cH)dCar , ,Са:!:
{
[X1nlAttribute}
p'Jbl i~ bcol c<!.n.W' 1 у;
[XmlAttribu t.J
public boolci13.hS!;!brnerge;
}
</ Jэ..mеЭВQТldСат>·
I
L
Глава 17. СвриализацияобъеКI0В 691'
х:mlFОПТtаt. Sбт .,ial ize (fStИ?alТl, !!1УСё1,ts),;
fSitrеiШ1. Cl:ose (J ;
ConsQle.ReadLins(i;
Превосходно! К этому моменту в!'1М дрткно быть поя:ятцо, Щ1К ИСFIQJJ,ЫЮватъ сер
ВИ:СiС~ри<щ:и:эаци:и объef(ТОВ Д/!Я ynрощ~ nPОJЦeсса сохранения И восста:цовления
данных вашего цриложенщr. Теперь ДaJЩЙТе ДЫЯСНИМ, IЩ.I:\ использова::гь ПWJЬзова
'1'eillIс:кие настрьЙRИ продесса серИ<)"лиЩIЦИИ.
сохраняемого объекта (это могут быть шraмnы временй, уникальные ИМена ИJ!И
ЧТО-l'О nиое).
дna .fIепосредет:веН1JОГО У"!астил J3 управлении процессом сериaJ1ИЗаци:и объек
ТОв пространство имев System.Rubtime.SeritJ.lization преД;1lэтает cneдиа.1'IЫIЫе
ТnШЦ. В табл. 1'7.2 описаны те НЗ них. о которых вам следует Знать.
692 Часть IV. Программирование с помощью библиотек .NET
L
ГJЩваl 7, СеРVlдЛизаЦI1Я объероs 693
Устройства
хранения
(фtjЙr.I, памrnъ,
Навl>lЙ 5eri<lli Z4\-l\3nIТllr ,
Поток буфер, Cl!жет).
~------------1 Форматгер
объект DeserialiJ:e .()
Обратите внимание на то. что для области видимости этого конструктора ука
зано private. Это вполне допустимо, поскольку форматтер получает доступ к это
му члену независимо от его видимости. Эти специальные конструкторы чаще всего
обозна чаются как приватные, чтобы обеспечить невозможность случайного соз
дания объекта пользователем объекта с помощью такого конструктора. Заметьте.
что первый параметр этого конструктора является (как и ранее) экземпляром типа
SerializationInfo.
Второй параметр этого специального конструктора является типом
StreamingContext, содержащим информацию об исто<щике или пункте назначе
ция битов. Самым информативным членом этого типа является свойство State.
которое представляет значение иэ перечня StreamingContextStates. Значения
этого перечня соответствуют базовой .композиции текущего потока.
Честно говоря, если вашей задачей разработки не является низкоуровневый
пользОвательский сервис удаленного доступа, вам вряд ли придется обращаться J{
I
i
L
Iлава -r7. СериаЛIol~аu~~ объектов 695
publi(: епuт 5trеаmiпgСШJtеztStаtеs
(;ro,s sProt,:'93 S I
Сrоз sMach.ine,
File,
Pe.r:s icr't.ence r
Remoting,
Other,
Clone,
СrО$sЛррDоmаitl,
All
}
[5е..\:'1 aliz·abl е]
olas5 MyStr.ln,gDat.a ; I3e:rializable
{
public striлg dаtаlte:пtОпе, dataItemTwo;
J
Обратите BI-щмаБ:ие на ТО, что при kнапОJШен~п'i" тuпа serial izaticnlnfo в ме
тоде GetDbjectDa.t.a () JЩ mpебуlЩ1CЯ, чтобы Э1lеме.нты: дшtЮ::JX 1taaывал:ись ОJU!иа~
ROI!() с :внутренними 'lлензми-перемеnцым:й Т1>ща. Это МОЖe'I' OЮlзатъс.ч пo.r-теЭЩ;11ti1
тогда. когда нуЖНО выделmь ДЗlmьtе из сохраненного формата. При зтом не сле
дует за~бывать о ТОМ, <ПО.дщI ПОJIy'iеющ значений из прив:атноro :tЮНСТРУI{1'ора ие
оБХОДI-{М:О ИСПОЛЬ30вa:J.Ъ имена, которые назначаются в ра.\1«ЮL GetObjectIJata ().
696 Часть IV. Программирование с помощью библиотек .NET
L
Глава 17. Сериал.lшщt1Я Qбъе:ктов 697
IOnDeser~alized]
.i. л t .e :rn·a l v od.dDnDes€,t iali z,e'ё/. (St ге:аюl rigСопt е хt 'с ол t е:rt r
j
/I ВJ.tn.on.!UIe~C:SI пс зааершевии ре1(ОЯС'1'р~1ЩИИ об'loeJt'1'i! .•
dа t аItеlrЮП<Z = dзtаJ tЭl1Ю пе . To1ower ();
da1:altemTwQ = dа.1;; аItеmТwО. Т о:Цоwеrt);
( 8:Е:Х i .a l 1: ,~aЫ e)
c la~ g IJз'\О- ;r P:ref;s
{
p I.J,b l.ic "t r: i пg gb j Ve Lsi ,rm = "'1.1)";
p Ubl ic СоnзоlеСu l0r Ба c 19 'If"u-ndС910r;
-public СолsоlсеСо1Э I For-еg.со'l1ТidСо] сч:;
рмН о UseyPrels ()
(
Б i.1 <
: itg;rщшd.dо l оr = 'e on 5~) 1eC 01 !) t . Hlack;
F'ore g:r o\in dCo lt.r = С' Qдзоlеr о lЬ r, Red;
[Serializable]
class lJserPrefs
11 ЯвлSQ)l1'С. нозыми!
public int BeepFreq;
public string ConsoleTitle;
public lJserPrefs()
{
BeepFreq = 1000;
ConsoleTitle = nМоя консоль";
BackgroundColor ConsoleColor.Black;
ForegroundColor = ConsoleColor.Red;
Sуstеm.Ruлtimе.Sеriаlizаtiоп.орtiопаlFiеldAttriЬutе.
11 ЯаJJQ'l'CR ИО8ЫНИ!
[Opt ional Fie ld.1
publi~ int BeepFreq;
[Ор;;. ionalFieldl
public .'3tring СОТlЭQlетitiе;
publlc llseIPref's ()
{
B,eepFreq =- 1,0 О О ;
Coti501e'Title = "Моя КОН С ОЛ'Ъ" ;
Вsсk-grщmdс,йоr = ', СолsоlеСо} o r. Вl "ck,;
Fоrеgrtюпd17010r = ~'')r:чю lе Соl О!;. R€d;
'}
Зам~.. аюre., Следует nOHi/lM'ClТI>, ЧТО иCfЮl1ьзоааНillе [Optiona lFi.e ld] не реш.ает проблему вер
,СИИ сохраненных объектов полltlостью. Однак{) ЭТОТ атри()утобг[)n~.. ивает решенИ'е самой ТИС
пичной l1PаблеМЫ(Д(j)(jаз.~ение "!овых r1OI1ей даtJflЫХ). Дnя реше.нИя более СJ10ЖIr1ЫХ задач ЛОД
деРЖКи версий .все же ГiЬтребуе·тСR реШJИЗациSJ интерфеиса lSe.r i а 1 izable,
Резюме
:в этой rлаве предпагаетс.н обсуждение сервисов сериэлизации. Вы MorJm убе
дй:г.ьсn в ТОМ. что платформа .NEТ для :корреi{Т]:{ОГО учета все.го множества СВН
зar-rnыx объеК:юв. подлежащих сохранению:в ~OTpJ{e. использует объектные гра
фы. Когда RЭЖДЫЙ "-иен объею-nото графа об6.зн;а,че;н атрибутом i·-S~r:1 аl i:Z аЫ е J .
rI
iI
700 Часть IV. Программирование с помощью библиотек ,NET
Р
,
азр~@Q,Т'llIКИ. не iще_;щn;в~ 'ШIbГ!<:I ра!'Ю1l"Ы t'; rI.:-'Jl;uтфо~IQЙ ,.N'E'I. обычно CtТllOM'I
,'N'ET 'J'{J.rLbIro rr 'срI;ДС::fвам J::~Дщmя ая't'е,рне;r-n:ри.1iIЩfim-ni:Й (noeHOJIblg ··
"1(1,'116 .вщЦJ?I'ИPJreп:'ICЛ 1: ·j~I':r~e:l1 »1, е1:lQТlll!'ТUБУ--Ющy"r..м пу.юграм:\1НJ:.YМ Dоо<;>:rreчeJ:,m
,NEJ'"
ем1. вы уЖе uмщш в~~\щщmг.Е, yQ~CJl :&'~M. "'!ТО это далeJ:ОО n~ nm.., Со>здaI-Iй~
vreъ. IIpЮIflЯmБии пй.Л.Re'ТDН lI;IЩfJ. fl.)t'lWi'j :rf IJче..щ. yвx-o~ (щ> ~oxtJ p4'JlXM;U.mpQ-
вaШIоvr) ..во~жВJfi.tтыD Wl"щрор:иы .~ В ]'IJ'("~~' iiI'fG~ '~'!!lфоРN11iЩЪJE ~Щjя'Ие р:1эра
ботчшm J.-ш:т; не :tj'Мею~ J~'fIЩ'[~'WОТО ндьгт,а. t;КiIJ&I'!'8'Ъ.I' пре,!{I'lQi.ТЦU'ать., <{ТО Wel)-
Gepllи.t.ьJ =~11. uбe~rre"Пf;!>.im'IТ 'fjдиш.'J:,ве:EJЩ:I'Й· еl'f~CQб В'Iam.щ(J~t:1'!mя ~ rд.iЩ~IМИ
й5ъP...кr~ Эru тоже '!1В {lОО'Т'Вt<:'т("'I'l"У~[J дei:i'с-rnИil't:'i,IЪ'JjЮ~m. J.1,сцьщ.3УН: OOCr..t'I УДa::iJ~И
JШrо в~:utШ'Тl'l'il.'i .NEТ. ~'1~ С'Тptl'Щ~I'!lДffорa.нroвы:е распред~деlЩЬЩ др",ло~
жeнш;t. ~ j~JIШ в:ичer~ ol'llцmTb С. ИТТ'Р JЩf!: »п. ,(еела вы ЭТОМ зЮt(:r:rнте).
П€p:RtJи за;цаll'}ciii; ВТ(JЙ щавы 1i"J!'iliяетсы P8ecмo~~ Юf:3,i;'.о~IJ:Щ-~,е!!!J:.ц( щ'm-lfJf1t
иоt"It'!Й, И-l!5Ш1лЫi)i""МШ; tp~доЙ CLR Ц.\!;ЕЯ treре,цJ1l.'q1И 'I.qflфоp:мa.щm ;ю гp~ доюt;.нщз.
nPШЮЖ~Н1-dt При Ьб~оfum:м;JЩа.тtf:'ПRО"О ~1>.\1QдеЙс:г13i:Ш ,1'lЕТ ..и1.'J'(Q~У
ется. ~mОШбdПЮ G,i1ецна.л:ыtЫ;!i;;ТI$:мп.шm, ~ 'Б:ак aг~ll'Т ,{me. pI'I.ЦУ-Мfl;ЦУl1h}, I;Дt:m.':r,
1Юii.ршалннг l!('J f'(jЫлse '(:ХctЮpЫЙ ПРО~ЙШJ~~t.>:'rt.m маpm;aд;кш)' -ДО ~щч.еFIШt'J.
'сеpIreРн:.ая шcrl'1Ви:...~аIJ,ИЯ: l'I'б'ьскюв Iв !ЗрОiU1Ш)IIOпroЖНОc::t:ь m:I'Иelз'f~ Щ"J'ИЩIЩ.щцл)
JjI 1:11;. lThcllre ~ЬШ(lн&m.я e)r.rИ эти::к G~h'tК. mрмm,ЮБ ЦуДеl1 Dре,!J,Лt'URЩlJ.m~€~К:{J
:npnмepQВ ~Ig ,по~;а.EiJlJIЮ\~ТРЙр'У;ЮJ,tiш п;рсщеre Пl:)С1:'рО~mп ра(щреДeJ[~-
1!ЫХ с'Исre),j( в Р8,юmос IIJlRтфйрмы .NE'f:
• , ]bia ,iJ;OMel'lfl щ:Ц),д](~же-~я оup-ед.е-д.ены "в рю.шах ОJIНШО 'U -r-йш же l1JlOц:t~
(И JТI)8!Т()МJ! на Qi!Шеf( и, roй же ~ЭN!JИне).
702 Часть IV. Программирование с помощью библиотек .NET
r
• Два домена приложения определены в разных процессах на одной и той же
машине.
ЭУВ tem. RU'l1.time. ReТ1'l0t.ing. ChaJYne 1з_ Тер Содержит nml:lJ, ИСГlользующие ЛРОТРКОJ1
тср для TpCllicnopтa сооБЩ6f-1ИЙ и объеl(rов
в УДВl1еl+НУЮ П)4КУ и ОбратНо
SУ5t,еш . Ruht i'roe Жешоti.ГiЧ .Contcexts По:reО,I1Яет itонфИГУРИРQВCiТЬ параметры'
объектногО' контекста
Sуstеш. Rш,t. i:ше .Re.mating .·Lifet;.irne Содерж.итПIПЩ, ~npавляющие ЦI'IКЛQМ су·
ществования УДaJЩI'IНЫХ' объвlI'ТОВ
Syzt.em. Ru:nt i.me.Rernoting. мessag.:!.ng Содержит 'rипы, IIIСПОЛЬЩI6Мые Д.ЛЯ созда
НИЯ tA передачи объеКТi!)В' сообщений
• агенты;
• сообщения:
• каналы:
• форматтеры.
Агенты и сообщения
Клиенты и объекты сервера взаимодействуют не напрямую. а через посредни
на , обычно называемого агентом (ил:и ргоху-модулем). Роль агента .NEТ Эalillючает
ся в создании для клиента иллюзии того , 'lТO он взаимодействует с запроше нным
удат1енв:ыrM объектом в одном домене пршюженuя. Чтобы создать Тal{УЮ иллюзию.
агент предлагает интерфейс (члены . своЙства. поля и т. д . ), идентичный интерфей
су удаленного типа. С точки зрения клиента данный агент и является удаленным
объектом . Однако "за кулисами" агент переправляет вызовы удш:rенному объекту .
Формально тзкой агент, вызываемый клиентом непосредственно. называется
прозрачнbtМ агентам (tгansрагепt ргоху). Этот объект. генерируемый средой CLR
автоматически. не сет ответственность за проверку того. что при вызов е удаленно
го метода клиент получит нужное число параметров (и они будут нужного типа) .
Поэтому прозрачный агент можно интерпретировать. как фикс ированный слой
в заимодействия. который нельзя программно изменить или расширить.
В предположении о том. что прозрачный areHT может выполнять проверку
входных аргументов . соответствующая информация упаковывается в другой гене
рируемый средой CLR тип , который называется объектом сообщения. По опреде
лению все объекты сообщений реализуют интерфейс System.Runtim e .Remot ing .
Messaging. I Message.
puыlcc interface IMessage
(
I D i ~tio na ry Pr oper tle s { get; }
Глава 18. Удадемюе ~заlfМощеЙQ1&l-1е .NEТ 705
кав видите, интерфейс lMessage определяет единственное свойство (с именем
properties), :котщюе обеспечивает дvстyn к RоллеIЩmf. ИСЩЩbl;jуемо.:й wщ ~aнe-
1ЩJJ предоcrавдевных клиеНТОМ аргументов. ПОс:JJе НIlПОЛ1Jения объекта сообще.
ния содержимым средой сш. он будеrr передан pOДCТ1lel:IНOMY пту. Щlзывае1l{ОМУ
реал.ЬНЬLМ. агентО.II" (теа! proxy).
Р~альный агент - это c.yIЦI-IOсть. которая фактиr.rеоки посылает объект соdбще
ElИJi В1!iЮfал (пон.ятие .н.анала будет о.бсуждаТЬСJl ниже). Реальнh1Йа.г~нт. к0'торый
(В Ь г.пичие от npозрачного. Ш'ента) мОЖет быть pl1ClJtupe1i програщМИСТОМ, пр~Д~
ставлнется базОВЫМ "l'ИПОМ класса С именем Re:alProxy (что и следовало ОЖJJдатъ).
Снова следует iюдчеркнутъ. что. среда CLR генерирует Ю!ИентСЕуЮ реюmэqцию
реалъПОl'Ciarента. для иСпользования по умолчанию. котораа впщrне ПОДОЙДеТ
-вам если, не во всех, то. в большинстве случаев. Но 't.lтобы им.ет1;. цредставление о.
функциональных возможностЯХ. предлатае.мых. аБСТР<lI\ТН:ЫМ базовым массом
RealP.r.oxy. Изучите фОРМaJffiное определение этоtQ 1:ИЩl.
Каналы
Поt'ле TOГO!l'.llli aгeH1ы проверят:и о"Iформатируют I10ставляемые ЮJИeJJ,том. аргу
менты, уцаковав их вооъект сообщения. с.ооП!етC'l'ВУЮЩИй. IM9S8age-совмеСТИМJ>IЙ
'РЩ передащ'(:нр'т реаЛ:ЫlоГО aгtЯl'Т8. объекту канал.а. liaналы - это сynщоC'tи. О,....
вечающие- за транспортировку сообщения удаленному объекту и. ec.'Ui это неоБJ.'О
ДИМа, 38. '1'0. чтоБЫ возвращаемое нначение от удале:аноrо объекта было доставлено
рбраТl:I9 юшеR'ty. В библиотеках базQвых Iwacc.OB .NEТ 2.0 предлагаются ГOТ9~ыe
реaJIИЗщиитре.х К'dНa:TIOВ;
J.
706 Часть IV. Программирование с помощью библиотек .NEТ
r
• ТСР-канал:
• НТГР-канал:
• IРС-канал.
с номером 80.
Наконец. в .NEТ 2.0 предлагается доступ к IPC-кан.алу, представленному типом
IpcChannel. который определяет коммуникационный канал связи для удален
ного взаимодействия с использованием IPС-архитектуры операционной системы
Windows. ВвидУ того. что IpcChannel при пересечеюrn: доменов приложений дей
ствует в обход традиционных систем сетевой коммуникации. IpcChannel оказы
вается намного быстрее, чем НТГР- и ТСР-каналы. однако. может использоваться
только для взаимодействия доменов приложения на одном u пюм же комnьюте·
ре. Поэтому IpcChannel ае может применятъся для построения распределеЮ-iЫХ
приложеНИЙ. допускаю.щих испольэование множества физических компьютеров.
Но тип IpcChannel может оказаться идеальным вариантом тогда. когда вы хотите
обеспечить наивысшую скорость обмена информацией между двумя локальными
программами.
Общая картина
Бели 'у вас CJT чсге-ния npедьщущих разделов .Уже T'o.rmвa идет .кругом.. "Не llШЩ
куйте! Проарачн:ый ateHl', реалъnый атент; об~' сообщения и диспетчер:вм мо
жете. МАК правило, просто игнорировать, noсколъ:кучаще всего вам вполне подой
дут параметры удалеННого взаимодеЙст~uя. пре;цлarаеМЪте по умолчанmo. Чтобы
аанрепить Б па.?dЯ.:I:И' соответствующую JIО~едоnaте'ЛhНОСТЬ событий. р::tсемагрите
рис. 18.1. на I(QTOPOM UQКfJ.$<ще I:;xeдm I1роцесеа: RоммУни:кации двух объе}L"ТОJ> на
раЗНblХ доменов n:риложещIЙ .
ОбъеlfТ удaI1енныи
кnиента объект
"
..
t j
Праэрачный
агент
ДИGneТt{eр
J
I РеалыныИ
агент .~ Н Формаrreр KaHal'1
,
Форматтер
I
I
1
708 Часть IV. Программирование с помощью библиотек .NET
Замечание. В этой главе тема расширения базового слоя удаленного взаимодействия .NET не
обсуждается. Чтобы узнать, как это сделать, обратитесь к книге Ingo Ааттег, Advanced .NEТ
Remoting (Арrеsэ, 2002).
L
[лав-а 1В . Yд~eHHoe 8ЗзИМоАеИс;.Т81Iе .NEТ 709
ПР11 ИСДQДЬЗ0вании типа,· отвосяn:tегося к МВR--объею-ам, cp~ CLR обеспечит
С0зданщ: в ДQМ~R~ приложения ЮIИeВТа прозрачного и реал:ън.ого aremOB. вто вре
мя" юш сам ~R-объeкr будет оставаться в домене npиложения сервера. При вы·
ЗО~f' методов удалem-ю:ro типа kJ:IИ.e1-ггом еистема yдaJ1С1-н[оto · взаимодеЙСТВИЯ .NEТ
(схема КQТОРОЙ описана ВЪШ1е) активизируется, "ЧТоБЫ вьmолнить задачиynаковки.
отлр<:itВкц и получения и:аформадШ1 при обмене даlUfЫми через границы домецов
прцложениЙ. Для этото МВR-объевтю имеют рлд ~воЙств. "nростирающихсJ'l~ за
ра~ши Щ фи;щ-чесного распо1iDЖени:я , Бы увидите . QTO МВR-объе>кты имеIOТ раз~
~e ош{ии конфигураЦии. 01:носяiЦиеся 1(. их активизации и ynраВiIецию ци
КiIOМ сущ~~твоВю-nш. Б арОТИВ(1ШОЛОЖНОС1'Ь этому. МБV'-объеICТЫ npeДСТaВ'ЛЯJQт 00-
бой ЛОК(1..'lЫfые lCоnыи удалепЙых объектов (испольэующйе прото.кол сериaлuзации
.,N'Eт. который был рассмотрен в главе ] 7). МВV-объекты: имеют намНого меыъше
ОIШJ'IЙ щшфигурации. пoctwЛl:ЩY их ЦИЮI сущоствавания }(ОИТРОШ1руется неuocpед
СТIЩННO :клиентом . Подобно любому дРУГому оБЪекту .NET. после того хах ЮШ~НТ
ОQВQбодит все ссъm:Ки.на MBV-ТИn . ЭТОТ ТИП станОВИТСЯ потенциа:;лыrым объектом
~lЩМа:ния ДЛЯ сборщика мусора. ПОСROЛЪНУ МВV-пшы ЯВ)1ЯЮТСЯ лоIщлbl1ыIщ КО
IЩНМИ удaJreПНhlX объектов, 'процесс ВЫЗ0ва.клиевтоМ: членов соотвеТСТБующеГ0
пша, вообще "Говоря. не предполагает никакой сете-вой активности.
СЩ:дУ~Т ПОНИJl..ШТЬ. что вполне естественным ДЛ1I еервера ЯВJlЯетСfl поддержн.а
дoi..,"1)'II2t R множеС'тву МВR- и МВV-типов. вы можете танже ДОl'адаться, 'lТO MBR-
ТЩIbl обiiP'IRо поддерживают методы. возвра:щаЮ1ЦИе раЗЛИ<UIЫе МВV-пmы. ЧТО . в
~eM-TO. НiШоминаег эвтома'1'изироваffilое предn:pиятие. где од»Н оо-рект создает
~ Bы'ыкaeTT другиесв.язаНliые оБЪeIffЪ1. Здесь возникает следующ»й вопрос : Юllt
~рн(}>игурирова'J)Ь пользовательскИЙ тип }{Ласса для ИСn()ЛЪ~О1ЩНЮl в виде МER
~ МВV-объе:кта?
Конфигурация МВR-объекта
MBR-об'Ь'еR'JЪ! не маркируютС'я специальным атрибутом .NET. а получаются
(нвно ИJШ. не.явно] из базового K.l'[aCCa s уstеtп .MarsI1a l BYRefQbj ect.
р.uы l сc cl t1!1s Sр оrtэ С аr Fа с t о r у t нa.r4hal;ByRefObject
! ... )
Формально тип MaJ::shaJ.By&efObje o,t определяется с)те.цуюlIЩМ образом .
1
71 О Часть IV. Программирование с помощью библиотек .NET
Член Описание
Замечание. То, что вы СКОНфигурировали тип в виде MBV- или МВR-объекта, совсем не означа
ет, что зтот объект следует использовать только в приложении удаленного взаимодействия, а
означает только ТО, что этот объект можно использовать в таком приложении. Например, тип
System,Windows.Forms.Form является потомком MarshalByRefObject. Поэтому при
удаленном доступе он реализуется как МВR-тип, а в других случаях он будет обычным локаль
ным обьектом в домене приложения клиента.
Замечание. Как следствие предыдущего замечания обратим внимание на то, что если тип .NEТ не
лредполагает сериализац~о и в его цепочке наследования нет MarshalByRefObject, то
такой тип может активизироваться и использоваться только в его исходном домене приложе
ния, Т.е. такой тип является kohteKCTHO-Связанным (см. главу 13).
I
1...
Глав'с!. 1В . Уl1аnеН'fIое взаимодействие' .NП 711'
с НИМИ. Коnечно. именно :клиент предоставляет слою )"'дa.J(е'JUJО]'О вааимод.еЙстви.н
ивфар.мацюо о CBOe.'III желании вззнмоцействовю'Ь ~ уда:ленным ТИIIОМ, но В ответ
наaanpос н.лиента серверное ПРИЛQ1Кel-ше имеет возможность срздатъ С'Оответ'стВу,
"
ющnи ТИI1 не сразу.
Замечание. ЛотеfЩl1aJJliffi>lМ ИСIO'If1ИКОМ недор~умений здесь l18ЛflетCJI то, 'пр в, лит~рiпуре, по-
священной . NEТ, BMeuтo, акронима WКO также используют ЭАО (Server Activated' Qbject - объ
ект, аКТИВ'и~руемы.й сервером). мрониМSАО ВСТРВ'Iзется в целом ряде статей и J<Ниr. 'О8язан
~ЫX с .NET В этой г"щве" В соотвеТGТВYlИ с современной ' теРМ1о1нологией, будт ilfспОльзоваТЬСR
з6брев'иатураWКО.
'3амечaииs. Всерда помните О том. 'fTO i(юбой WКQ·rиГ1 должеfj иметь KOHCTPV1<Т0P , зэданны.М ПО
УМОJP'jЩ'j ~ip!
L
ГпаВ~1! 18. YAaI1B/Hi.oe' R~аимодеtlCтвие . NEТ 71 3
боримеl91ЦИХСЯ возможностей, ~ табл. 18..3 пOJtазано. как WКO- и CAO-dбъеI<ТЫ со
отноСйТСЯ: С вариантами J;lО!;lедеЩi$J. "ROторыt>тол::ыro ЧТО бьmй нами рассмотрены.
Тем не менее, чтобы упростить изложение материала этой главы, мы с вами по·
строим и YCT8.l-Ю'вим общие компоновочные блоки. содержащие как необходимые
метаданные. так и ClL-код реализации.
Замечание. Чтобы выяснить , как реализовать общие компоновочные блоки в рамках указанных
выше альтернативных подходов, прочитайте книгу Тот 8агпаЬу, Distributed .NET Programming
in С# (Apress, 2002).
l
Глаед 18. УдаJlеЮWEl взаимодействие .NE1 715
'lIsing sуэt:еm;
Jlsiл g sузtеrn. Rt1Лtlmе. Remot ing;
using Sj'э .tеm. Runt ime . Remoti:ng • Channel s;
uS2ng Sys,t em. Rtmtime. Remoti.ng. Channel s. Ht tp;
usinqS1щр~eRemеtingAsm;
1
716 Часть IV. Программирование с помощью библиотек .NET
namespace SimpleRemoteObjectServer
(
class SimpleObjServer
{
static void Маiл(striпg[] args)
(
Conso:J..e.WriteLine("*** Нiiчало работы SimpleRemoteObjectServer! ""*");
Со nsol е. Wr i tel,ine ( "Для завершения нажмите <Еп te с>" ) ;
Метод Main () начинается с создания нового типа HttpChannel. для которого ука
зан произвольный идентификатор порта. Этот порт открывается путем регистра
ции канала с помощью статического метода CbannelServices.RegisterCbannel().
После регистрации канала компоновочный блок удаленного сервера может обраба
тывать сообщения, поступающие через порт с номером 32469.
Замечание. Номер, который вы назначите порту, как правило, выбираете вы сами (или ваш си
стемный администратор). При атом , однако, следует учитывать то, что порты с номерами ниже
1024 резервируюrся для использования системой.
L
Глава 1.8, Удаленное 6~аИМDд~йств~е .NET 717
дnстyn ж СООPlетс~щPJМ ВОЗМОЖНОСТЯМ. Здесь снова создайте ПpQстое кен
СО.i1мюе придожеии~. Установите ссЬi.1Щy на ьу'9 tem. Riшt iro е . Rero~t i n: g. dll и
SimpleRemo tirig AsТfI. dll. -Реализуйте мз ifl О так. :кав nо:казако 1iиже.
COI1'Sole. Wri teLin€- ( ..,.... ~ На-чало раСю ты Si mp l eRemot~Obj ес tС liелt I " . .. n);
СопS.оl е. Wri teLine.( "для завертеlilo1l'! .нажми-:rе <Er,ter>") ;
11 CosAA~e ИО&О1'О HttpChannel.
Н ltрСhаf.юеl с = new l!.t :cp·Cha!lLl>=l 'О;
Ch ani:\elServi ce's .• Regl!'/terthanl'1~l (с .) ;
1
в ЭТОМ ПРИЛrui~еmm ЮIиента o(\)pa'Т~Te внимание на следующее. Во·первых., кдц
ею таюке ДОлжен зарегистр"Щ)овать НТГР- Rанал.. но идентификатор порта ПРИiЭТОМ
не указьшается.. поскот.ку ROНечнан тОчна Rанала ЗаДается адРесом U:RL активи
зации. аостэвля:еМ1;IМ :клnеFi'rОМ. Пос1ЮЦЪRy клиент взаимодействует с WKO-l'ИПОМ.
ВЫ должны ЗЕТ.ющзировать коЪЩтр~ТQР типа, заданный по умолчанию . С этой
целью .вызьtвается метод f\.cti<rator_GetObjeQt () .с двумя парам'етрами. Пер:аьц.f
параметром ЩlJLч:етсц ин:форма:ци.я цrnа yдauешroго объllli1"Э, с :которым вы хотите
"ВэаимодеЙе'Гnо~аТD. ПрОЧИТ8Й1'е цо~леднее предложение еще: раз. nOCItMbJ<y' здесь
метод ]"c,tiva.tot .GetObject () требует M~aд"cIнныe onиtания объеl<Та. станОВiJтел
'пено. nочемудщi клиента rnaк.ж;е трфуетс.я ССЫJШа Н'а общий компоновочный б(JЮК!
В Rol-Щ't' r.lIaвbl БУАУ1' раеСМОТрt:НЩ' различные возможности соверmеНС1'lщващiЯ по
веделИS1 :компоновочного блока мцента Б ЭТОМ оТн.ошении .
1
718 Часть IV. Программирование с помощью библиотек .NET
Тип ChannelServices
Итан. объявляя существование удаленного типа. сервер использует тип System.
Runt ime .Remoting .Channel s . ChannelServic es. ТИп ChannelServices предлагает
небольшой набор статических методов. призванных обеспечить содействие в про
цессе регистрации канала удаленного взаимодействия и обнаружения указанного
URL. Thaвиые члены данного типа описаны в табл. 18.4.
Вдобавок к методам Regi s terChannel () и Un registerChannel () с Щ ясНblМJl
названиями. тип Ch a n nelServices определяет свойство RegisteredChannels.
Этот член возвращает массив интерфейсов IChanoel, каждый из которых пред
ставляет дескриптор соответствующего канала из тех. которые зарегистрированы
Члеu Оп:м(;ание
Uп:r:еgistcеr Сhаnпеl (J Метд,· Dтменяющltlй регистрацию ДOHHora кан.ала 1'1 У@ЛЯЮЩl1И ЭТОТ
канал .из ОllИ~1(8 зарегистриРованныХ
Нап видите. lЩЖДЫЙ ханвд nолучв.ет попятное СТРОJшвое ИМЯ. а ТЩPRе СВО:Й
уровень приоритетС!. Например, ~СДИ; добавить в метод Ма i n () приложе»ия
Si mplёRёmоtеОЬjесt<;:liеnt слеДУIQIЦУ19 прогрaммнyIO, логику
ТО в OIте коJiСQЛИ ltЛИ~llта ВЫ увидите вывод. ПОДОQ~ покааанном:у .на JlИС. 18.4.
1
720 Часть IV. Программирование с помощью библиотек .NET
г
Тип RemotingConfiguration
другим IUIЮчевым типом удаленного взаимодействия является тип Remoting-
Configuration, который, в соответствии со своим названием, использует
ся для настройки различных параметров nриложения удаленного взаимодей
ствия. Бы уже видели этот тип в работе на стороне сервера (при вызове метода
RegisterWellKnownServiceType ()). Другие заслуживающие внимания статиче
ские члены этого типа описываются в табл. 18.5. а возможности применения неко
торых из этих членов будут продемонстрированы в оставшейся части этой главы.
Член Описание
GetRegistere dActiv ate dClient Type s () Возвращает массив объектных типов, зареги
стрированных на стороне клиента для удален
ной активизации
WКО-ТИПОВ
WКО-типов
11 lWвo~ ИВформацмн.
foreca.cb. (Wel1Кr1:ownS'erviceTypeEntry wko in Vi\YOs)
j
Совsо1 е. Wri tеLinэ {"J-f...мJ1l ~лока, содерж",щего WKO: {О}" I
wko.AssemblyName);
.cons,o.le .WriteLin.e ("'URL да}1НО го W!<(J\J (О f", 'WKQ·.Object..!J'J:1 );
.Cor,sale ..Wr,i,teLine ( ."ТUr1 W!<O: [О)", wko.ObjectType);
Сь!') sole , .>'11' i t.eLiIH:~ ( "Р.е!ЖИм активизап.ии WKO: (().I "., w.k a. MQde);
I
i
ь-
ThЗ.ВQ 18. УдалеЮ10е ваакмодеЩ:Т8ие .NEТ 723
1. На М8'f!IИНe сервера создайте и о:rkpОЙ're для дос'ryIm пшmy.1J которой буду!'
Содержатьс.и кaмnОНODоч'ные блоки серверной С'ООJЮНЫ.
Замечание. Вместо n.онятного имеЮ1 Машины URL аКТ~l!иза1Ш1II ~ожет ук.аЗl;oIвать ее IP.eдpec.
Использование ТCP~1(aHanOB
в настоящий момент ваш УД3JIffiiНЫЙ объект ДО(,'ТJIIеи череэсеТt'I!QЙ ПрО'I'О:КОЛ
Н1ТР. Как уже ynоминалось выше, ЭТОТ ПРОТОВ;QЛ впошre COBмeOT~ с бранДМауэ
ром. но .-еверируемые при э.1'ом: пакеты ЭОАР H~OГO QраздY'FJ>1'~ (по причине ·пред~
ста:в.ilеНШi данных в форма-rе XМL). ч.ТQбы уменьшить сетево;й трафmc, ЫОЖНО из
менит1:. КO:МnОffовочные блоки клиelt-rа и сервера так, чтобы в юп ~СJ;I~ЛЬЗОВался
1СР·1tанал и. следова:ге.лы-ю,nш BinaryForma'tter, Бот подход.mцan модифmaщии
компоновочного БЛOI11а с.ервера.
Звмечание, Для файJюв с ОПр.е,целениями объехтов, .ДОС1Упных П.О ТСР-каналам о Эaд8J'lным URI,
чаще всего (1tQ не обязательно) иqщmьзуетЬя рааширение "i<. retn (от remote -удаленный}.
:8 ЭТОТ же файл. Единый файл" .config. содерmащий I'I настроfПUI у~еmюro вз;а-
имодеiicтвия " 111 информацmo привязftИ. ДOJ.iЖe1I RЬШlЯДетъ примерно так.
1
726 Часть IV. Программирование с ПОМОЩЬЮ библиотек .NET
r
Создание файлов *.config сервера
Файлы конфигурации на сторон:е. сервера позволяют объ,явить объекты, кото
рые будут доступны ДЛЯ удаленных вызовов, а также задать параметры канала и
порта. Рассмотрим следУЮЩИЙ вариант программной логики сервера.
<configuratior,>
<system.runtime.remoting >
<application>
<service>
<wellknown
mode="Singleton"
type="SiJDpleRemotingAsm.RemoteМessageObject, SimpleRemotingAsm"
objectUri="RemoteМsgObj.soap"/>
</service>
<channels>
<channel ref="http"/>
</channels>
</application>
</system.runtime.remoting>
< /configuration>
Обратите внимание на то, что значительная часть информации удаленного сер
вера указывается в контексте элемента<service> (не сервер!). Его дочерний эле
мент <wеllknоwл> использует три атрибута (mode, type и objectUri) для регистра
ции WКО-объекта в слое удаленного взаимодействия .NEТ. Элемент <channels >
может содержать mобое число элементов <channel >, которые позволяют опреде
лить вид канала (В данном случае это НТГР), открываемого на сервере. Для тер·
каналов вместо h t tp нужно просто использовать лексему tcp.
Поскольку в этом случае вся необходимая информация содержится в фай·
ле SirnpleRemoteObj ectServer. ехе. соп fig, метод Mai n () серверной сто
роны значительно упрощается. В нем остается выполнить только вызов
RemotingConfiguration .Configure () и указать имя соответствующего файла
конфигурации.
l
L
Глwre 18. УД3JJ811IЮ$ взаимодеЙСfВие .NET127
Работа с МВV-объектами
Наши первые приложения удаленного взаимодействия позволяли дос1j'II кли
ентов к одному WКО-типу, Напомним, что WКО-типы (по определению) являются
МВR-типами, поэтому доступ клиента к ним осyrцествляется через агента-посред
ника. В противоположность этому, MBV-типы являются локальными копиями сер
верного объекта, обычно возвращаемыми открытыми членами некоторого MBR-
типа. Вы уже знаете, н:ак настроить МВV-тип (следУет обозначить соответствующий
и.ласс атрибутом [Serializable]), но МВV-тип в действии вы еще не видели (если
не считать обмена строковыми данными между двумя сторонами). для иллюстра
ции взаимодействия MBR- и МВV-типов мы рассмотрим новый пример, в котором
используются следующие три компоновочных блока.
namespace CarGeneralAsm
{
11 Этот 'l'Иn ЯВ'nRе'1'СЯ: мва- об>ъеlC'1'ОИ I обеспечивauции доступ
11 IC СОО'l'Jlе'1'С'1'8YJOЩИИ мвv~'l'Иnаи.
public class CarProvider : MarshalByRefObject
{
private List<JamesBondCar> theJВCars =
new List<JamesBondCar>();
l
Глава 18. Vдаяеtlное ВЗQимодействиl'! ,NEТ 729
11 Добав.пвниев аписе!\: несхсшьJCИX 1IiI1IIИИ.
puыcc CarProvider!)
j
Сопsсlе. WI i t'eLi.l"ie ("СDздание постаВЩИR!а маш .......н" ~
;
theJ!3CarS.Add(.new .JаmеэЕОi":\dСаr ("QМ.obile",
'HO,tru.E, t;r-ue));
theJBCars.Aqd(rI6W ~ТamеsВо[)dCаr'("Flу€>-r", 140, tr\::le, false~);
trlеJзс2.I:s.А<1i'jlпеw ..Jащ6sвQndсаt("Swirnmеr", 140, falS€, true));
theJВCars. Add (nа'оН ,Jа.m.е$'ВоцdСаr ("Ba$ieJВC". 1.1 О, false, talse)·).;
Тa:J\Ш,( образом. ДJlfj всего сод(;ржимоro 'ГJ1Цa List<> буде'r ИCnО:П.Ь30ШЩ марша
JIЩil' 110 значению (если содер.жащи;еса в нем типы тацже допуqнa;IOТ ееР~aJШза
цию). Это очень удобв.ая ocol1leRRocTb удален.н:ОI'0вз~одеЙствИ'я .NEТ и ЧЛ~НОВ
библиоте:к ба;'.lОВ~ ]ЩН.ссов. Бдор<Ц!ок l't п"ль:\ф:вате~ МБv- и МБR-nmам, КО"
торые вы можете ооздать Сами. Ш9бой тип и;3 би.блиот~ б~ОБщ..'!: ]щассов, сопро
.важда.юЩИЙся аТ]';Iибутом ISeri а 1 izable J', танще с:аособен БЫСтупать в 1tЗ.честiзt'
МВV-T:mтa :в архитск:rуре удаленного 1Iзаимодеи.отЕЩИ ,NEт. АшщОГИЧFЮ. :люБQJfТflJТ.
долучающцйса: (не:посредсТВfЩНО ИДИ RDeEieИRQl щ~t'1аrshаlВуR€fОЬj eet, мож;ет
ФУШШ;ИЩПiipовать, щm МВR-тип,
ЦЗl.пg Syst.em;
u,51ng '::'.уstеП1_Rl.1пtiцц~. Rempti 1:19;
liSi ag S ystern. R(1Il tiше • RenlOt i ng . Сhаnnеlз;
ц:эing System.R-сщ tirn!E' .Remoting . Cnan.ne 1з, Bttp:
1:15209 са:rGenеralAзm.;
730 Часть IV. Программирование с ПОМОЩЬЮ библиотек .NET
r
i
паmезрасе CarProviderServer
(
class CarServer
изing System;
using Sуstеrn.Ruпtimе.Rеmоtiпg;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using CarGenera~;
using System.Collections.Generlc;
namespace CarProviderClient
{
class CarClient
{
private static void UseCar(JamesBondCar с)
{
L
Глава1В. Удаленное взаиМОД~ЙС1аие .NFГ 731
Consol е .Wr± teLine ! 11-> Имя: {.о},", (;. PetNa..l11e) ;
G0!'1so1e ...W"L"itеLiле ("-;> Мак;:; . с:корастъ; ('О)", с. MaxSpeEC) i
c:onso], е. Wri teI,ine (" -> ('п@собн":)(:''I!Ь Т1JIa8q.Th: {О J ., 1
L:. isS",aWDrt1'1~') ;
.сопsоlе .W:r{teLirJe (Н._> СлоС.обаость лет"iть: 101 ''',
с. iз1"1 ightWоrtЪу ) :
с.ошsоl€. Wri teL.iле.(} I
вызовов клиентов).
Чтобы проиллюстрировать соответствующую конструкцию и использование
САО-типов. модифицируем наш уже имеющийся "автомобильный" компоновочный
блок В нашем МВR-классе Ca!:'Provide!:' определим дополнительный конструктор,
позволяющий клиенту передать массив типов JamesBondCar, предназначенных
для размещения в обобщенном списке Lis·t <>.
publi c class CarProvider : MarshalByRefObject
(
private List <JamesBondCar > theJBCars
= new List<JamesBondCar>();
<copfiguratio:c>
<~Y$\em , runtiro", ,remoUng>
<applH:ation>
.:;se!'vice>
<асНva.tj:!dtype ;:: "CA()CarGene;~~, Car,P~ov.i.der •
CAOCarGene:ra1.ASIn" 1>
<lservic!'J>
<c'hanпеl,s >
<channei rеf="tсрП роrt="~24б, 9" />
< /chii nnels>
<I аррН<С'аиоп>
</ ::;ystem. !'t,!ntime. rеmо:tiлg>
</СОf1fi'gШ-д tion>
Обновленный файл *. с о n f i
9 :клиента также должен иепользовать элемент
<activated>. а не элемеwr <wellknown>. Кроме того, свойство url элемента
< с 1 i е n t > теперь должно укаэывать адрес зарегистрированного СЛО-объек
та. Напомним. что при регистрации типа CarProvider сервером в виде WКO
объекта. клиент указывал соответствующую информацию в рамках элемента
<wellknown>.
<configuration>
<systern.runtirne.rernoting>
<application>
<client displayName = "CarClient"
url = "tcp://localhost:32469" >
<activated type =
"САОСаrGeпеrаlAsш.. CarProVider, САОСаrGeпеrаlAsш." />
</client>
<channels>
<channel ref="tcp"/>
</c hannels>
</ application>
</system.runtirne.remoting>
</configuration>
Чтобы "жестко· запрограммировать запрос СЛО-типа клиентом, можете исполь
зовать метод RеgiэtrаtiопSеrviсеs.RеgistеrАсtivаtеdСliепtТуре (). как пока
зано ниже.
Член Описание
__ _ ___L
Гnава 18. Удаленное взаимодеЙr.;tвие, .NEТ 737
Для И·.JIЛlOетрации особwностdi JЩэинга по умодчапию длл YAa.i1:CRПЫX САо
тщюв И WКО-сингдетон ЩIР~eJ.IИМ в нащем те:кущем проекте CAOCa:r;Gener::alAsm
ho-вьЩ :ЩIУТре)'JНИЙ I:Щас(' ы,is-еlnn fo. Статичес1ШЙ член 1.easestats () ЭТОРО клас
са ШiIВuдит 1Пiформацию о те1()lЩеМ JllI:зинге ДЛJ11'ипа Car:provider в окно ROHCQ-
ли сервера (н~аабудьте указа.ть дцрективу t1,.ing длн пространства имен 5ystern.
ЕUDtimе..RеП\о·!i:ir,q.Lifеti те. что(iы с;ообщиТJ~ коМI1ИЛЯТОРУ о месте нахожде'f-ШН
щ:rределeд.W3. типа IlсеаБе).
Тm<ой цодход может быть полезен тогда, KorAa домен приложенин: клиента готов
начать выполнение длительной операции в потоке. использующем удаленный тип.
Например, если одно поточное приложение должно напечатать документ. содер
ЖaIЦий 100 страниц текста. очень велика вероятность того. что удаленный САО
тип или WКО-синглет может выйти за рамки отведенного для процесса времени.
Надеюсь, вы уловили оБIЦyЮ идею. хотя здесь. I{онечно, более "элегантным" реше
нием является создание нового потока выполнения.
Суть в том. что перед тем, как пометить ненужный тип для отправки сборщику
мусора. среда выполнения проверяет. не имеет ли данный МВR-объект зарегистри
рованных спонсоров лизинга. Простыми словами. спонсор - это тип. реализую
щий интерфейс ISponsor. который определен так. как показано ниже.
p ublic i nter Ea c e System.Runtime.Remoting.Lifetime.ISponsor
{
Time Span Renewal(ILease lease);
Б любом С--луч3.е. если. .к.J:IИевт И.iDI сервер желают о'Гм~нить с;понсорство" ЭТО
можно сделать с помощью метода I.Leas e. UnregisterO . ВЩlР1'iмер:
/ / ~~ние спонсора дn. ,цаниоro об'ЪеХ!1'8.
itfLeas€ 1 nf о . иI1 Т !;)g :i5 ter (ЩУSР О П$О r) ;
о:казываеТGЯ немного бо:лее ОЛОЖНЬ!М . чем ПРQСтая сборка мусора. На стороне пре ..
имущее тв мы имеем wtIJЮlCuе воэма:ffi;НОСТИ удрaвлeIIин ОТ1:JОСИТtmЪно того, КОТД8
1~[3
--~ 'ii
S 'ii
~J
ADaиInI:
~~.~iI'hir:n~~ l8i1I
trж1..
1
746 Часть IV, Программирование с помощью библиотек .NET
Установка CarWinService
Установка CarServ ice. ехе на мanшне (локальной или удаленной) предполarает
выполнение двух действий.
installutil carwinservice.exe
После установки сервиса Windows вы можете запустить и сконфигурировать
его с помощью аплета Services (Службы) Windows, который размещен в пап
ке Администрирование панели управления Windows. В окне Services выделите
CarService (рис. 18.10) и щелкните на ссылке Start (Запустить), чтобы зarрузить
и вьшолнить соответствующий двоичный файл.
storted
l
Главе 18. УДaJ1еюнre sзаимодеЙСТ1Jие .NET 747
этого ограничения. при испo.JIЬзовании ns.д,JЩ поддерЖЮI удаде:нного 1fЗ8ИМодelit
ствия необходимо выnoл:нrrtь следующие дейc;rВия.
1. На жестком дисне создайте новую папку ДЛR храневин GarGеnеrаlАзm .• cll1.
Вэтои пarше СОqД8Йте подкаталог \Вiл. ско.пирyй'rе файл CaтGenera<lAвm.dll
в этоrr подка;гадor fiffi.npимер. С; \ПSСаrSеrVl'се \BiI1}.
<СОПfigurаtiОП>
<31''' t.em. ruпt il1\.e. rеmоt:Lлg>
<.appHc~ t ion>
<ser\'iG€>
<w'e 11. kflown
Iтюdе=" SingTetOB"
'ly-pe= "t-arGеn.еral.АsR1. Ca.rP IQ'oТide:r::, СаrQenеIв.'lАsЛl"
:ОЬ:I ect~jrj ="сз·rргоvidеr. Боар" J>
<JэеrVlсе>
< сlылш? 1 s>
<clIarme1 уеЕ=" J]tt_рп 1>
<.} с·flёlлnеlз;;.
<:/applicat io·l'1>
<1 systern. п1:tJ time, re:тotiDg>
<./еоп1iguгаtiФп>
// Создание делегата.
GetAIIAutosDelegate getCarsDel
new GetAIIAutosDelegate(ep.GetAllAutos);
/ / Асинхронный вызов GetA1lAutos () .
IAsyneResult ar = getCarsDel.Beginlnvoke(null, null);
L
Глаза 18. УЛ11.11еflное взаИМОД&ЙСТВl1е,NЕТ 749
свойство IАsуtюRеs.ul t . IsCornpleted ПDзволяе:т :ВlilЯСНИТ~. завершил ли раБОту со
ответствуюЩий Me:roA). После завершещrя работы ~~~нтa вы получаете список
list<>. возвращеннмй методом C,s,rPr.ov ider. G~tAllAutos О 'в результате вызова
члена Ehdlnvoke (). и передаете _кaжд:blЙ объент Jamf;';1.sBondCar ста'ШЧ"ескои вспо
могател:ьной фунтщии с- им~нем US€C~,r ( ) .
j .isSe.aWorthy) ;
TIaIt\eSpa-6е- CarGeneI;al~sm
i
v'Ubl i c cla.ss Carp:to'Jtder t1a:r.sha:lBYRefOpject
(
Резюме
В этой главе были рассмотрены варианты конфигурации компоновочных бло
ков .NEТ. IIозволя:ющие совместное ИСIIользование типов за рамками одного при
ложения. Вы увидели, что удаленный объект можно сконфигурировать. как MВV
или МВR-тип. Именно от зтого, в конечном счете. зависит ТО, как будет реализован
удаленный тип в домене приложения клиента (в виде КОIIИИ или с помощью про
зрачного агента).
При конфигурации типа для работы в качестве МВR-объекта перед вами воз
никает целый ряд соответствующих вариантов выбора (WКO или САО. синглет
или объект одиночного вызова и т.д.). Все имеющиеся варианты были рассмотре
ны в ходе обсуждения материала данной главы. Также были рассмотрены вопросы
управления циклом существования удаленного объекта. реализуемого с помощью
схемы лизингового управления и CIIOHcopcTBa лизинга. Наконец, снова была рас
смотрена роль ТИIIОВ делегата .NEТ, используемых для аСИНХРОJ-lliОГО вызова уда
ленных методов (и здесь такой вызов по форме оказывается аналогичным аСЮI
хронному вызову методов локальных ТИIIОВ).
L
1
ГЛАВА 19
Создание окон
спомощью
System.Windows.Forms
Е ели вы npочитми пре.дыдущие 18' глав. В1У должны ИМеть ~ОлиднyIQ базу ДЩТ
использования нзьma rrpоrpам.миров·щrин С# и арХИ'J'a<Jj-РЫ .NEТ. ВЫ, ДОН~Ч
НО же, можете 1IpИМ:енит.ь шщуч:енные энанНя д,1ПI построения КОНСОЛЬ~ ЦP~(Г
жений сJ1е;дующего поколеНИJI (кaR сд-уч:ноI). :60 B~C. наверное. больше ИJ;I'J'ереqyет
создание привлеюпельного графического ицтерфеt;icа ПОДЪЗОВ8'.геля (GUl), КРТ<фЫЙ
позвошrr пользователям взаимодействовать с ЩlIпей сщt:·темоЙ..
ЭТа tлава является первой азтvex I'лав. в HoTopЬL1I: обсуждаетсf.j: процесс постро
ения ТРaдlЩИоН1НЫХ приложений на oCH!i1!Ie иcnо,ц:ьзования тЭR назъmае.м;ых форм.
Вы узнаете, }(ак С'оздать »выQNохудomecтвеmюе"" rnавное OJCНO, испольву,я lЩaссы
Р'огт и Applicat],cm. В ЭТОЙ главе -rаюке доказано. как.Ц KOIJTeКCTe GШ-окруже
ния выполнить захват nОЛЬ30ватедъскоro ввода и ОТВ~ИТЪ На него (т.е. обрабqтать
событии мЫШИ и кла.вйатуры). НаЮ)]Jец, вы узв;аете, к!щ вручную или с l;ЩМОЩью
инструментов npоектиров;цшп. ВL"'ТроенЯbIX. В Vi~uaJ. ·Studio 2005, RQ~етруировать
еистемы меню, панели :внструментов, С1'роJtи ооС';тоlfIНИSI J.l интерфейс МDI (blultiple
Document Interface - много.дшtyментньtй интерфейс пршюже1;ЩЯ').
• Диалоговы.е окна общего вида. Среда Windows Fonns предлагает целый ряд
стандартных заготовок диалоговых окон для выполнения типичных действий
(OpenFileDialog. PrintDialog и т.д.). Кроме того. вы можете создавать свои
собственные пользовательские диалоговые окна, если стандартные диалого
вые окна по какой-то причине вам не подойдут.
КлаСС.,1 Описание
Applic·ation Класс, инкапсулирующий средства ПОРдержки
Windows Forms, необходимые любому приложению
r! a:me5pa~e My WiOOOwsApp
{
public (Jla's,s МаiпW1Л .dоw F"orm
754 Часть IV. Программирование с помощью библиотек .NET
...
Гnааа 19. Создаl1И~ ОКО!1 t помОЩью Syst~m :W\n.dоws.fоrmэ 755
Сiютемой по умолчанюо!,), В О'l'JЩ'<J;ие от дрyгщr. .средств р8зработЮi гра.фическоГ9
шrreрфейса от МicroS'oft. которые :ВЫ. :возможно, и~пOJJ1.ЭовМИ ранее (В час:mос'l'Ц.
это касаетсябя.бJЩQТeКИ 6а30ВЪЩ RЛассов МFC) . теперь lleт необходимости сщrзы
lIать ~отни ·строк .npoГР8JЮdНОГО JЮда ОООТВОО'C'fвующей Шlфраструюуры (фреймов ,
докумeн-rQй.. представлений, приложeIПШ и .нарт сообщений). в QТЛИЧИ6 от прило
женйЙ "'in32 ЛPI. использующих С. :щесь .нет необходимости Вру<-UI)'Ю реа;щзОБЫ
BQ7Ъ процедУРЫ WinPI;oc () и wi (l~ain (). в рамках платформы .МЕТ эту ·гPftзнуЮ~
рабо'ry' выпоmцuот элементы, ИН:КaJТсу.;шрованные- в ТШJaX Form и Appl i c at.i.ofl.
п·атеэраое Му WiCJ.elФwsАрр
{
11 Гариое oJtНO.
рu,ЬН С. clasB Иа iriWi r!dow : iform \ )
11 ~1iПt'%' пpИnо~.
pLJb lic SЦitiс. с lа з s Prog :ram
{
5·t atic VQid I'!,.H n ( ~t .t :i Jjg [] arg sJ
!
{! Не sаl!SУДЪ!l'е о 'us'inq' ~Я: SYStelll.Windo1!rs.Forms!
:i\ррliсаt:J.оп • .R!.iП (rlew MainW.indow () 1;
Кроме метода Run (), этот класс предлагает и другие методы, о которых вам следует
знать.
Свойство Описание
Star tup Path Содержит значение пути ДЛЯ выполняемого файла. запустивше'го дан
ное приложение
L
Глаза 19. Со~д.аliие окон G пDмQщы0 S'.ystem,Windows,F'o'rm8 757
• ИСDолъэоват;р 3l:1ачевия, BeI<O'ТOpЫX атрибyroВ уровня КQМnOНОВО<ЩРГО бдока .
l1sing .system;
US-iI:!'g 81'е tem. wi.hd(;)IiIБ . Form$;
using Sузtеrn:. ~~fl есН сп,;
(ж 1
1
758 Часть IV, Проrраммирование с помощью библиотек ,NET
Делегат System.EventHandler
Обратите внимание на то. что событие ApplicationExit работает в паре с де
легатом Systern.EventE:landler. Этот делегат может УI{азывать методы. соответ
СТВУЮ1ЦИе следУЮщей сиrнатуре.
Замечание. Класс ЕvелtА rg s является базовым ДЛЯ множества производных типов, содержа
щих дополнительную информацию для событий из определенных семейств. Так, для событий
мыши используется параметр MouseEventArgs , предлагающий, например, такую информа
цию, как позиция (Х, у) указателя . Для событий клавиатуры используется тип KeyEventArgs,
предоставляющий информацию о текущих нажатиях клавиш и Т.д,
,
I
l
Глава 19. Создание (}1СОIi а помощью System.Wlndows .Forms 759
"Анатомия" формы
Те:перь, когда вы понимаете РОЛI.ТIШaАррliсаt i6tl . CJlе.цующеЙ вашей задачеи
является непосредственное раСсмоТрение фуmщионвлъrtых ВОз'можностей кл.асса
Fo r m. Как и следует ожидать, RШl.CCJ FQr:J;!:lнаследуе1' больntинство своих функnио
нальЦliIX 1юзможнос.теЙ 61' родител:ьских КJ1aC€JOB. На рис. 19.3 показ3НО окно dbJect
ВГ0тег (В \'i~щal StHdio 2(05). в :к.отаром отображается Цепочка наследования про
И~ОДВОГО.l)1' Forrn типа (вместе () набором реализованных ин;rерфelllсов) .
...,- - - ....
,,'-рUЬ.Чс c~ l'OrnI • svstem.W-.iJ!i(,~;€brrta{I1'...соI1Ь'tlj
'" /42m!шr 01. SY5t'eт. windows. Pomi!>
/
,' ~
...... ID!фТNie,l
.. Renfбenrs а ~',lПdt?'o'Ji ;йf m.k!g D:Ct)(,that ,m;I/tPJ'i,ip ~" ioplic-'atfo ,,'~
."" [6;\",т,м;z6""~~,,, , I $ f f'\tl!П;I:;Ej.
.-> 'W1r.~~I\(~ ('
' 'ь _'01 {GDr.~*
I
--:,~Ы~
__:~,! .
р"с. 19.3'. Г1роиt<:хождени"" TI~na J'or.m
Полвая цепочка наследо:вaнИf,{ ТЩIа F'orm включает в себя М'Ншкество базовых
:классов и ИБтерф~со.8. но здес:ь cдeдy~ подчерклуть, -Что ;вам" чтобы стать хоро
IIIИ.М раэработчищ)м ПРИJюжений Windows Fолns, совеем не обязаmeлыш ЛОl:IИМaТЬ
роль ЮlЖцого члена всех РОЩГГe,тJЪС.ff.Ю( f!ЩlССОВ И кащдоro реали;JOВанного интер
Вы. Я<'J,Щ'рное, eaм~) поцимаете. что подробное опвса:ние каЩДОГО члена всех
RJШ.ССОВ во цеnoЧЮ' н;аслед:ОВЩlИJ'{ PD:j:'m потребует от.цел:ИюЙ вольтой m-rигИ. "Важно
r.o1 и Form.
понять общие хара.lfl'ери;С';rики поведения. предлагаемого ппrами Солt
Все неоБХ{jдимые подробщ)ст~ о €оответtтвующих .нл:аr:сах вы сможете наmи в до
кументации .NEТ Frшnewoг)t 2 . О SDR.
760 Часть IV. Программирование с помощью библиотек .NET
Syste m. Wi ndow s . Forms .Contai nerContro l Обеспечивает контроль фокуса ввода для тех
элементов управления, которые могут высту
пать в качестве контейнера для других эле
ментов управления
Sys tem. Windo ws. Рогтэ, Form Представляет любую пользовательскую форму,
дочернее окно MDI или диалоговое окнО
Свойства Описание
L
Глава '19. СtJздаНJ~е окоН с nОМОЩЬ1D S'Ist&hl.Wlndows.Forms, 761
Dкr:JНЧВНМ ' 'Гв(i1/. 19.4
Clойотва Описание
En.a,b led, P'c>cused, Visi.ble Каж,nое из ЭТИХ свойств ' во~вра.щает Зliа'iечие типа Вf)оlеа'П,
укэзь!sаюLllее соответствующую характеристику оостояния
~neMeтa уnравлеf1ИЯ
1
762 Част!> IV. Программирование с помощью библиотек .NET
p ublic c l a ss Ma1 n Wi n d o w : Fo rm
(
p rotected override void OnMo u s eDown(Mo useEventA r g s е)
{
/ / Добав.nеlUlЫЙ npограмииый ход ;ЦnЯ; соБЫ'l'ИЯ MouseDown.
Кроме методов вида О пХХХ ( ) . есть несколько других методов. о liоторые вам сле
дует знать.
1
Глава 19, GQ3ABHI:1IJ окаl-i о rтОМОЩЬЮ System.Windows_Forms 763
IJsi пg $Yls,tem;
и$ it!'g Эу:stещ. Win.dows _Е'оут<; "
l.Jsing Sу.sЬ:em.Па:а:wl ll g i
ГliilF.le'Space MyWindQwsP..:p,p
{
P l1bl i::; ;;:l ass Мai..в'IIНщl0 W FэсUl
\
1" L,bl i t;: Иа:lt [1 w1 rн;u.oM О
I
1/ ИСПОЛЬЗование J.laC:n~.щ>"eJIЬ1X ~O~<;:ТВ' ~ УC!r&Иовхи
/1 хараж'.1'8рХСorиx интерфейса пcmьзо:sа'1!eJ1Я.
'T ext = "Ноя фаJ-.r:т·Оj'(::тич е,С1~ая форма " .;
8ci\jbt = 300,
"W idt.b = :',0 О ..
BackColor = "Color. LffiпоJ'l-,;::hН fоn-:
Сн:rэь r = Cbl rs-ors. Ba n.d)
J
Свойство Описание
Button Содержит информацию о том, какая клавиша мыши была нажата, в соотвеТСТ8ии с
определением перечня MouseBut tons
Clicks Содержит информацию о том, сколько раз была нажата и отпущена клавиша мыши
Delta Содержит значение со знаком, соответствующее числу щелчков, произошедших
при вращении колесика мыши
pl1bl.i о J.\1aiлl'Нпdоw (J
(
Свойство Описание
KeyCode Возвращает клавиШный КОД дnя события KeyDown или события KeyUp
Modifiers Указывает, какие модифицирующие клавиши были нажаты «Ctrl>, <Shift> и/или <М»
Shi ft Содержит значение. являющееся индикатором нажатия клавиши <Shift>
Свойства Оnиcatlие
1\.cce pt.В\ittQD Чli1Тает или уотанавливает информацию о lo:ifjопl<е:, КОТОРЗfJ будет "liвжвrз"
(В форме). К<:1ГДЗ п.олыювзтелы нажмет lUJавиwу <Enter>
MaJt lmi ze:p.ox: Ис пользуются AMI \1lfформациl'1 о ЖtJ1И4ИИ У формы К.IOЛОК минимизаЦИИ
HinimizeBo.;t J/I максимизации окна
S I:юw Di аl 0'g () Отображает ФОРМУ!! 8t'1Ae мода!l~НОГО" диалогового ()tt;НЗ, Более поДРОб
но о проtраММ1IТрова н ии диалОГО8Ы~ ~ЖDН ГОВОР ИТС9t В ГЛCIВ8 21
768 Часть IV. Программирование с помощью библиотек. NET
События Описание
Activated Происходит при активизации формы, Т.е. при получеl~ИИ формой фОI<уса
ввода
Closed, Closing Используются для проверки того, что форма закрывается или уже закрыта
Deactivate Происходит при деактивизации формы, Т.е. когда форма утрачивает теку
щий фокус ввода
Load Происходит после того, как форма размещается в памяти, но пока остает
ся неВIiIДИМОЙ на экране
ем работы программы.
Событие Closing работает в паре с делегатом СапсеlЕvеn-tНапdlеr, определен
ным в пространстве имен System.ComponentModel. Если установить для свойства
Глава 19. Сuздаffие ОКОН с ПОМОЩрЮ s.ystem,wjndows,.For.ri1s 769
cancelE.ventArgs .Can·c eI ~Ч~ЦИ~ tтu-e (истина), фОрМе буде:г даноуказани-е ВОЭ J
врamться к .нормальной раб9те, и форма униq'IоЖена не будe'I: Если установить
дл.и CancelEventArgs .C(!.1'\cel з~а't{ени~ false (ложы1. будеТ crенерировано. собъi
'!ие Closed. и Щ)}1Jl(Уj((ен;ие WiцdQws FbrrЩi будет эаверmeRО (дОМен npилvжеНия бу
дет выгружен и соотве1'СТВУ19:ьЦий 'Процесс преttрвщев).
Чтобыэацрепить в :па:мятп IJосщщрвателъН0СТЬ с:об.ы'ГИЙ.l1роисходящих в рам
ках цикла существоваIiИЯ ФОР.NlЪ1. рассмотрим новый файл м.ainWindow.cs. в КО
тором СQ6ытШI LOiid. Activated. De~ctivate, Closi.ng ИСlоsеd обрабатыВaIbТСЯ
в ROнструкторе Юl8сса тав:. lЩR nO'liазанЬ ниже (не забудьте ,цgбавитъ в пр()грamvry
директиву usi1'\r;j' ДJЩ ЛрОС'J"PЫiСТ~ -имев Sуstеш.СоmропеоtМО.del. ч;roбы получить
доступ:к щrрeдe;n;еmпQ CdncelEven·tArgs)~
publ:i" Ma:inForm ()
I
/I ОбрабО'1':8:iI рi!UI.!rИЧИI.DI: 0о6Jin'ИЙ1J;ИIШ" с=ущеС'1'8.0ВёUUCI: Формw.
Clos{ng += new СаПс:е1Еvеf\.tИаhdlе:ё (:м а in Роr!Т'._ С;1 o$ ing) ;
Load +~ П$"" Еvеnt.Ва,nЩ?J::(МаinF9IIТ1_Lоаd);
CLo.sed += пеw ElJ'entНal1dler {МаiпFр:пп~С10зеd) ;
bttiva'ted 01,= new EV?1it!:1dпdlеr П1аinFоrnL_Асtivа:tеd);
Deac ·t:Lva·t~ += l1ew EventHandler (Ma.inForm_Deactiv ate) 1
p'!"i v a ·te vaid МOi iпFсптn_СID-s ir,g (::ibj ect S.епdеr, Саnс:е 1 EventArgs е)'
I
D.ialogR~s'ult dr =
меs. ваgеВо!К. S,how 1 "ВЫ ДЕЙСТВИТEJI:ЬНО хотИте заr.рыwь ПрИЛОЖение? "'"
.. Сбб!,j!.I'ие С1 psirlg ! "., MesElageBo&Bu t tOl1S . YesN'o) ;
Н (dr == D:i-alоgRе.su,lt. N'o)
e.C:ancel = t-ru8;
е.1$0;;;
е .Cancel = false .;
т
ПО Часть IV, Программирование с помощью библиотек .NET
ГХ!
Соб",т", Load
Сoбыn1e Activate
СобыТ118 De<lttivate
Событ ... Activate
Coбt.mI&~
CoбыТII8 Activate
co&.rn1e oeac~vP
СoбooIтне. дaiуже
Сабыт", Deactivllte
CDбt.mo: Adiv~e
событие C:JOSed
ок
Создание Wiпdоws-приложений
в Visual Studio 2005
в Visual Studio 2005 предлагается специальный таблон для создания прило
жений Windows Fonns. Выбрав шаблон Windows Аррllсаtiоп при создaFШИ проекта,
вы получите не только объект приложеFШЯ с соответствующим методом Main () , но
и подходящий исходный ТИП, производный от Form. Кроме того, среда разработки
предложит вам целый набор графических инструментов проектирования, способ
ных превратить процесс построения интерфейса пользователя в детскую забаву.
Чтобы рассмотреть имеющиеся возможности. создайте рабочее пространство но
вого проекта Windows Application (рис . 19.6). Мы пока что не собираемся создавать
рабочий пример. так что можете назвать зтот проект так, как захотите.
L
Глава 19, СРЗА</ние окон с помощью S~stern.windows.fQfms 771
ProjKt~:
"- .----'"........:.
"1,,"J~""'Cz
_
... - ~ -- - -
- - - \1
T"""~'
.м...i:~~'~;;";_~
, --- - '.-- -.- .---.-
\<,lПd"",..- 1,
'j, '~martD'e,u
11
-
Da_
~ ~bo
Те>1 A1Ui<a'tlon ,I;~--аt!Q~
D1O"'ibu~ >;,-.1011' S<ilunoo.
, '" Otnl<r ~'
I Jiit o,&.ffpro_~tТ~
'''' TS! Рг~Ш
!:-еагт onr~
i""-oI.,,,•...
fiJ",.1 11_
, j>~\I!r
~~ip
.; ~t-lp
L S-!а~1IiII
'j,"T~
L.iTd~r
1i'! ,DiIfa;
.~Юl[,iiLf. . ,~
A,~Pt6utton (поле)
Aa:..sibleDe.criptk>11
Aa:eS$lbI.N"","
AcceSSlbleЦoIe D<!fouIt
д!IQlvOrор F~
дUIDS...~ Font
дuloScroll False
mAutoScrollM",gon О. О
mAu!OS<;oI1МIn~ О. о ~
-- ~~-.: ~.,.-:~--.,-~: -=- - ~"':',- ~- -=-§: -.::- .-....;- ":"'-;0<.
• AII Windows Forms (Все злементы управления Windows Fолns). Здесь вы найде
те полный набор элементов управления Windows Fonns, включая элементы
управления .NEТ 1.Х. которые считаются устаревшими.
1' - ~ .~ ~; \
1 ,О T~ ' !iYOIenL'WJndo.... ,1'GrW C,,'Progam Ro5~~crOS<ifl:~1!ы!I aw
R.! T""I!< ~~tem:lI'lindo"' •. F"'1Щ C; 'flogr'_~''i''1IcrыQft ~ &!!Jdi '11
[
"~ И
I О тoтerМГilj МIa_f1, ~~CO/Тil"tIbt." "'Qb"lд<Se!l!bl1 ~ i I
11'
t 0, Т_ .sys-.',~$.FOI1!'J; С,'f'r_~Уo!iqoюft"""""I.s~:
~ TDQi8a, S~.,:{ndC\IJS.f~ G:,\f?rQgr""РdО$'#'1I<;"",ft V1ШЫ:5tJdi i I
I
О Tdar"""",' !'ЮQ$Of\.\'~СOПlP6th... GIObal_v Gad1e '1' I
8 T~trip S:ys~~i!5,F_ Ulilb.>1 ~'Y ca<ho! I
.i T~~~~~~•..•.,;,--.-.
FiIer.
- _с'.:ю~.:~.~~<"
------,,---
::~_I. _
._G1o!>aI,--~'I1bI~ c,orh~ >,,": Ij
l
1'~~" ~._,, - ~ ---.~_ .. ~, -,,, ,,, ,1 ;\
1----'- ......... _ _ _ _ _ _ _ : _ .. ~ __ _.. _
T....J8"ar
&cWso!... J
Vt11ion! 2,0:0,0
IЖ ,j[ cМ'~ ][ ~ ]
3амеiolание. МО}j(е1показатъся, 'ЧТО 8 CnI'lCK& во/<ие д.обавnения элеМВЩОS 'улравпения имеютtя по·
вторе~IИЯ !наГlример, ДnЯ ~лемента yn:pаtll1е~IИj:J 'I'oolBa.r). На саМОМ -же деле 1<.аждый Эllемент
списка yt'IИ,кален, так Ksl< соo;rветсrвующий ~лемеJ.П упраЩlения мIJIЖет иметь другую ВSIЮИЮ
(например ,.: 2 .0. BM~ТO 1,0) 11/1iIЛ11 быть элементом .NE1' Compact Framework. ЛоэroмуБУДЬt:е
внимательны , 4тоБЫ 8bItipan. правW1bR,b1И Эllемещ.
;~~~t~!.~~щ~с,:"",м.,
;3 ~ TкtVI..
liI' (.\1 Properties
,*' ,.. Reterenreo
!:! §а '4Ciiм' В'
't.1 Form 1.DeSlgner.c<
.Jd Progrмn.cs
namespace муVisuаlStudiоWiпАрр
{
public partial class MainWindow Form
(
public MainWindow()
(
InitializeComponent() ;
L
Гnа,В8 1:9. СDзд.i'IR~~ окон О nомощыо 6ysfJJm ,·Wln.dows, Рогта 77fJ
3амечакие-. Bcerдa Jiy\:t~ neрёименовать ра3мещаемы~ 3.11eMef4T уrф&!tl1e1iИЯ'. перед тем l~aK про'
rpat.iMI.1P0GaT\> обработку соБы11ll •. Ес:tlи этап).не
CAt;!'fIBJt., ВЫ, JЮt\)"ШТ. е Целый нвб.ор обработ~
'IИКОВ ОQбы-tи~ С неинформвт",вн.ыми имеi'\ЭМИ I:fвподоБИ'е but tоп2 1. (:1 ick. ПЩ:I(f!JЛbJ{'у при
ССЩДЗtЧl'1И СООJsеn::тв),ющеге имеыи ЛРУМ'ОJ1чанию к:И~ злer.ffiнlja ilpoctb до.баВ1fЯeroЯ суф·
ФИМ: в в"'де hClJJЯДКDВОro НОМ8ра переменной,
J
p.wUc МaipfJiliH(\OW О
t'
ЭвмечaIOf&. Кa)fl,Дbliq эneмеl~Т ут;1pщ;i/Ilffi!'\.'1J'I иМ'~е'f свое сабмтив ЕЮ УМD:J1Ч8Н.IIIЮ, J(Ol'op.oe будет об
рабdтюю при ДВQЙНО.м ЩеЛ4ке ЮS ;ЛОМ ЭЛ\!МеКТ~ ynра:влеlШI1 в ·окне n'poeк;rl4p<>ga~ll4.R ФtJР.мbL
HanplII"'~.. собьrr.ием 'ПD УМОi'lЧ,ан~JO ДnA формы ' является L0 ~d.· так ч:то :если выполнить Д!:tОЙ'
ftОЙ ЩеЛLJ.Qк" поместив укаЗiП"SЛЬ МЫши ~Ia ,~n Р'().!'т... cpe.!1~' раэра60ТИИ 2IIITO/:d€lnN6CQ1 ~.аПИЩ!ifj
I'1ррграМ~~IIiIЙ -кад AТlfJ обраfjОiКlIr име~ эt.ого соБыi1я•.
1
...,......
!
Класс Program
Кроме файлов. связанных с формой, Windоws-приложение Visual Studio 2005
определяет еще один класс, представляющий объект приложения (т.е. тип, опреде
ляющий метод Main ()). Обратите внимание на то, что в следующем методе Main ()
вызывается App1ication .EnableVisualStyles (). а также Аррl ication .Run ().
static class Program
(
[STAThread] static void Main()
(
Application.EnableVisualStyles();
Application.Run(new MainWindow());
Замечание. Атрибут [STAThread] дает среде CLR указание обрабатывать все устареешие СОМ
объекты (включая элементы управления ActiveX), используя SТА-управление (Slngle-Threaded
Apartment - однопоточное размещение), Если вы имеете опыт использования СОМ. вы должны
знать, что SТА-управление используется для того, чтобы доступ к СОМ-типу выполнялся в син
хронном (а значит, безопасном в отношении потоков) режиме.
L
Глава 19. СоздаН'ие окон' с nOМС)щ!'Ю Sys.tem.Windows.FQrms 777
различных :fшстрУМеитов p~ npо.еR.ТИРо.вaнюr. но е<::JIИ. требуется. то есть во.3.
МОЖН'О:СТЬ обработюъ ее :и ВрyчflyЮ.
ЧТQбы привести npимер ИСПо.льзо.вания элемента ynpавлениs M!:3rtIJSt:rip. со;'!
дайте НОВ.ое npи.'10жеиие Windows Fbrms с ИМбнем Мещ1striрАрр_ lЮместите &JЩ
мент управления Mell.uEtrip в фо.рму В окне ПРОeI~ТИРОВания. црисвоив ему им-н
mainMenuStrip. В резулшате в файл ".Designer.cs Jtобавцтс.я :новая nере:менная.
-х
t""'дl1~~!~
~ ~R!!<.J~"'"
"",:k. iTop v
C".n.~ ,.fdd...,
--------------~
• Вставить Wстanдартную" систеJ\oIJ меню (Ffle. "БаУе, TOQls, Help и т.д.).. испо.льзуg
ccьt:lUCylfisert $tandard IteJТ'!$ (Вставить стандаРТJ:JЫеэлементы).
~.• lJk'Ii"oМerIuStrip
Замечание. Вы, наверное. знаете, что символ амперсанда (&), размещенный перед БУI<ВОЙ в стро
ке элемента меню, задает комбинацию клавиш для быстрого вызова данного элемента. В этом
примере указано &Файл~В&ыход, поэтому пользователь может активизировать меню Выход,
~tажав сначала <Аlt+ф>, а затем <ы>.
//
/ / xnenuStripl
//
this.menuStripl.Items.AddRanqe(
new System.Windows.Forms.ToolStripItem[]
this.fileToolStripMenultem});
ГЛЗВ~ 19. Соадание окон с помоЩЬЮ System.Wind·ows.Forms 779
!I
/1 flieToQlSt.r'.iipМenUIt,em
1/
this. filеТЕ:юlstriр.МеПUltеm.DЕорDоwnХtеша.AddRangе (
t\e.w Sуstеm:WiпclО.W'э ·.Fоrт.s. 'l'tюlStriрltеm[ J (
this. ех} tToolS'UipMen1J1t~m}) ;
1/
/I МainWindow
11
·t..l1i S • CQDtrdls. Add.( this. meh-u-s:tripl J ;
publi'C Маiлwind.оw ()
(
1
r
I
I
780 Часть IV. Программирование с помощью библиотек .NET t
I
~ IМinМenustф
L
780 Часть IV. Программирование С помощью библиотек .NEТ
k. _ _ ____. _ _
с ·~)кt~~)-,..;;;tРt;;';I~'i!М;~I~-- ~ .- ~ - -'"ix_;
I
I
Это IwнтeRCTHOe менш преДназначено ДiIЯ то.го, чтобы rnЩЬ,эоватедь МОГ выбрать
размер ШРИфl1'а ДJIJI ~оdбщения, отображаемого в обnасти клиента ФОРМЫ. Чтобы
упростить себе задачу, создайте' ТИП перечнл TextFont.Si ze в PI4~ цространства
имен МеIщst1:~рАрр и ООЪЯ:ВИТеновый. член-перемепную ЭТОГ0 типа в pmvmax Fo:mn
(устано13ИВ для перемеНffОЙ значение :['extF.ontSize .FontSi zeti!orroal}.
лamеsраi;;е MainForm
r
/ / ВСПQlllоr~am.JD1Й П8р8'Lень ДJ1" pa!blepa ШРPlфorа..
en·aтn 'J'extF.ontSi-..;е
Следующим шагам НВШlетсн обработка CQБЫТИf.\ Pai fJt, формы с IЮМQЩЬЮ окна
свойсТВ. Как будет показано в слещrющей rлаве, со'бытще Painl': поавОJlЯет ОТООРIl-
1
r
782 Часть IV. Программирование с помощью библиотек .NEТ
this.ContextмenuStrip = this,fontSizeContextStrip;
Гnаев 19. СоздаН14е 0,1(011 с ПОМОЩЬЮ Syslem.Windows.Forms 783
Если в:ЬШnЛНИТЪ ПРl-ш~жение теперь, ВЫ СМQЖеТt: изменить размер отображ~.е
МDтотекcrОВОГО' СDОбщения по щелчку правой кноl1Ю1 мыши.
Чnем Описание
Давайте расшир.ам I:I:щnе :КО1'I.~кстно~ М'СНЮ' так. 'ЧТобы в нем ридом с выбран
ным в настояm:иii момент nyщcrом менюотоор~аct, oтмe-rкa IIЫfiopa. Установить
отметку дщt данногоэле.мСljта медю Qчень просто (для этого ну-жно УСТaJ{ОВЙТЬ
Значеl-ше С'ВОЙСТБЗ Checked paВHJ;Ц14: ·t;rue). ()ДВа:ко Д;ЛЯ ТОГО, Чтобы проследитъ, 1(<1'
КОЙ II)l1IКТ меню должен быть отмечеI;f, ПО1'ребуется дополнительная программная
J10rиI01. Одним иэ ,60зможaых ДOДXGДO~ ЗДflСЪ яВЛi.fIется опредeJiение специальной
пере..чеННQЙ Торl,$.triРМе.РllItщп, которШJ будет представлmъэле:мент. ОThfечеttпый
в аастоюциii момент.
public MainWir,:dow О
j
11 Ваcms.цуeиJoIiir ме'1!о,ц ДJIJiI. цеитрировaIIИи ФОРIAI.
CeТJt e rToS'creeiJ
();
lnitiali2eComponent1);
784 Часть IV. Программирование с помощью библиотек .NET
r
11 YC'l'aHosxa О'l'Ие'l'JCИ 81о1бора дn_ Э'n_И8Н'l'а М_IШ 'Средний'.
currentCheckedltem = normalToolStripMenultemi
currentCheckedltem.Checked = true;
currFontSize = TextFontSize.FontSizeHuge;
currentCheckedItem = hugeToolStripMenuItemi
if (miClicked.Name = "поrmalТооlStriрМеПUltеm")
{
currFontSize = TextFontSize.FontSizeNormal:
currentCheckedltem = normalToolStr i pMenultem;
i f (miClicked.Name == "tinyToolStripMenuItem")
{
currFontSize = TextFontSize.FontSizeTiny;
currentCheckedltem = tiпуТооlStriрМеПUltеШi
}
11 YC'l'aнosxa О'l'ие'l'JCИ 81о1бора д,n_ ноэоrо эпемеН'l'а.
c urrentChe c kedltem.Che c ked = true;
Ра'бота с StatusStrip
в дополнение к системе меню :мноrие формы предлarают поддержку CТТW01(U.·CQC
rrюяJd.Ui.. ~оторШf обычно разМеЩаетсн в НИЖНеЙ части формы, Строка сm:тtJяmm
моЖет делиты:я па любое число "nанелей" (;: текстовЬй (или графW<Iесной) информа
цией, содержащей пояснении Д..1IВ пyнк:rов меню, текущее времи. или спецИалЬные
Да1-шъtе прюroжеНИЯ.
Хотя подцержка строк СОСТОЯНИЯ (с ПОМОЩЬЮ типа SysteEl. Wiпdо.WS., FormS.
Stat.tJsB,ay) предлата:етсн с момента появлеНИяnлатфор:мы ,NEТ•.B .NEТ2,O вместо
простого элемента Stah1sВ.ar предлагаетсн ИCIIQ,m,зовать НОВЫЙ тип Start1JsStrip.
Подобно обычной C"I'poKe состояния. StatusStrip может состйятъ из любого чИс
ла панелеЙ". содержащих 'ГеКСТDвы~/rpафические дaннbre, предоставленные тИПОм
'r'o.olStripStatus. Однако St.at\JsStrip может содержать и дополНительные эле
менты, Н3Примерf следУЮЩего В:ида.
Настройка StatusStrip
Добавьте в окно проектирования формы элемент управления StatusStrip и по
меняйте имя этого элемента управления на mainStatusStrip. Следует понимать.
что по умолчанию StatusStrip не содержит вообще никаких панелеЙ. для добав
ления трех панелей МОжно использовать разные подходы.
I
1
L
Гпэва t'9. Создание !)ХРН О ПDМDЩоlO Systerti.WimJDws.Forms 781
... .
• Г,/Н,,1 _ ~ х
0:0;' •
1-~-:'fIb:Je
f ..
i Dodc _ .
~~-_.~---
... ,.. ~ ~ :.. v,- " ... ; •.. ". ~ ... ).... ~ .....•.• _ •.• ~
;;;;\ _ .........1 i I_~ ....",........... \
i ~ IJ,,,~
,.-. '.' ... .._."....--.. _.
;; ~~'IU!\'~''t'!
~-
t r.
!
j ~~I b~
'I~ _
_~ __-- - - . . . . ._,__...._ ~ . _____ ~-. . __-~- .- --
Рис;. 19.1 в.. Добавление элементов с lТомощью раскрывающегося
меню tювbIX . злементов stа1шs5i t.:riр
,
p:ri,,",ate v o i d Inl t ia1i.zeComponent (.)
11
1/ mairtStatusStr.ip
/1
788 Часть IV. Программирование с помощью библиотек .NET
this.mainStatusStrip.Items.AddRange(
new System.Windows.Forms.ToolStripItem[)
{ this.toolStripStatusLabelMenuState,
this.toolStripStatusLabelClock,
this,toolStripDropDownButtonDateTime}) ;
Чтобы настроить панели так. как показано на рис. 19.19. нужно установить
подходящие значения ДЛЯ соответствующих свойств в окне свойств Visual Studio
2005. в табл. 19.12 для элементов StatusStrip предлагаются описания свойств.
которые нужно установить, и событий. которые нужно обработать (вы, конечно.
можете настроить панели та1(. как сочтете необходимым).
3наЧ"ение свойства Image члена tооlstriрDrорDОWПВuttоnDаtеТimе может
указывать на любой файл с изображением. размещенный на вашей машине (при
этом. конечно, следует учитывать то, что СЛИIШЮМ большие файлы изображений
могут по рождать проблемы). Для натего примера вы можете использовать файл
llappyDude.bmp, предлагаемый вместе с загружаемым исходным кодом для этой
книги (посетите раздел загрузки Web-узла Apress, размещенный по адресу ht tР ://
www.apress.com).
L
rfltJB8 19. СОЭДilние oroht t ПОМОЩЬЮ sуs't~m.Wjndоws . FоrIТ)Э 789
Таблица 19.• 12. Конфигурация паН8щ!iii .3ta'tusS.trip
События ,цnЯ"
Члеt\-перемеНН1IR панenи Свойства АЛ1I УСТ8НОВICИ
обработки
tool St.r ipStat, UsLд.Ье liФ~!lцS·t аt~ SJ?rlng=true Нет
Text = (ПУСТО)
'rextAJ.i.g n = TopLef"C
tOolStripSta t.usLabelCloc k BQrder~ideв =All
Тежt = (пусто)
Работа с ТYlпомТimеr
НanОмним. что Средня.я часть строки состо~нин дол.щна отОбражать текущее
время или те1iy.1ЦyЮ дату. в зависимости от предпочте;н;ий подьэовате:n:я.
Первый шагом на пути к достижению этой цели .явд;J!ет.сн доба:вл.ение й фор
му ч.лена-переменноЙ Tirnce r - КОМпонeн:rа.ВЫЗЫВающ~го некоторЫ'Й метод (уна
;Jанный С ttoмощъю обработчика соБЬJтин. '1'ic k,1 через ;заданный интервал вр~мени
(указaнm:ilЙ .с ПОМОЩЬЮ свойtnа Interva1).
Перетащите I{омпопент Time'r в О1що npоеКТИРlJjва:ни.я формы й переимену"Йтt'
ето 1) ti1DerDateTimeUpdat€: . :ИCnOJlЬВ)'я оIШО G~ОЙ~:г13., установит-езначение свой·
(:тва Intе:ь:vаl равным 1000 (это зна.ЧeJ-ще в МИЩIИсщrундах). з..зНз:чени:е С',войства
Enablecl-· paвнblMtrue (истина). Наконец, обработайте событие Tick. Перед ре
алиЗацией ОQработЧИRa событий Tick oдpeд~тe в проекте новыIй тип переЧЮ1 с
именем Date'I'imeForma:t. ЭтОТ перечеиь, будет ИСЩЩЪ30'ваться д,!ш выяснения то.го.
что должен отображать вТФройэдем:ент Т.оо1 ~;a, r ip3.t p tu sLa1J:e l - текущее вре:мя
шти re:кущую да'l)'.
enurn .D ateTi1'l1eFotmat
I
Юю wСlосk,
SbowIJay
.1.
790 Часть IV. ПрограММl1рование с помощью библиотек .NET
Включение отображения
в этот момент обработчик событий т i с k должен отобразить в панели
toolStripStatusLabelClock текущее время, если значением по умолчанию члена.
переменной DateTimeFormat является DateTimeFormat. ShowClock. Чтобы позво
лить пользователю переключаться между отображением даты и времени. обновите
MainWindow так. как npедлarается ниже (заметьте. что здесь также указано. какой
из двух пунктов меню в To olStripDropDownButton должен при этом отмечаться) .
L
Глава 19. Соэдание OKO~ с ПОМОЩЬЮ Svstem.WindtJ.ws.FoJms 791
pri vat€ vo1.d da:yo:ftlleWeekToolзt;r ipMefl\:iltero_ Click (obj ect э:еndе-r.
Evei'JtArgs е)
{
11 УС'1'8Ш)ав:а 01l'КQ.'1'ЖИ и форJJta'1'& }:(&!1'JOI д.riJI' niUteШt.
(:щ: ren-tСЬеdre,jI'tеm. Checked = fal$e;
dtForrna t. = DateTirneForma t . БЬо.wDау;
currentCheckedItem = 'dayof-t.hеWееkТ.QоlSt.r iри~rщ:ItElm;
(;!UIJ;8ntC:heckedI tem. Cbecked = t.rue;
р'!: i va te void ех.}. t'Iaol S'tripJ"1eI)uTt~m_ Мo1iI&e~over ' ~obj ect sender,
Even !:ЛУЧ;; е}
( 1:,001 Strip5la.t:usLa-ЬеlМеПUStа,tе. Text
= n Bы~ ОД из ЛРИЛО. жейия _'''; )
Итак. у :вас есть оБRО1mеШIЫЙ npoe.ll1T )щя тестового З2шуСRa. Теперь при выборс:
rtyc1кТО1l м«no ВЫ ДОJIЖНЬj: видеть в первой пзвели элемента Statu$S:trip соответ
ствующие строки с ПОЯСНН10щей щнfJOрмациеii.
Состояние готовности
НанонеЦ. нужно гарантировать. ""(То цр}! снятии указателя мыши с DyfIRТa мещо
:ruшъэова.телем в первой теиетовой Щ\Н~ не останется -старая" ПОДСRaэJta. а. б);дет
отображено некоторое МТIшовое" сообще,fIИе (:вanp:имер: "Ожидание действий пощ..-
1
792 4асть rv. Программирование с помощью библиотек .NET
зователя"). 8 текущем своем виде наше приложение оставит в строке текст, соответ
ствующий ранее выбранному пункту меню. что может вызывать. по меньшей мере.
недоумение пользователя. Чтобы исправить это. обработайте событие MouseLeave
для элементов меню Выход. О программе. День недели и Текущее время. Но вместо
генерирования нового обработчика события для каждого элемента. позвольте всем
указанным элементам выэьшать одШi метод с именем SetReadyPrompt () .
private void SetReadyPrompt(object sender, EventArgs е)
{ toolStripStatusLabelMenuState.Text
= "Ожидание действий пользователя."; }
Работа с ToolStrip
ТИп ToolStrip В .NEТ2.0 предлагается использовать вместо типа ToolBar.
предлагавшегося в рамках .NEТ 1.X и теперь считающегося устаревшим. Вы эна
ете. что панели инструментов обычно обеспечивают альтернативный способ ак
тивизации соответствующих ПУНКТОВ меню. При щелчке пользователя на кнопке
Сохранить. результат будет тем же. что и при выборе Файл~ Сохранить из меню.
Подобно MenuStrip и StatusStrip. тип ToolStrip может содержать множество
разных элементов панели инструментов [возможности использования некоторых
из них вы уже видели в предыдущих примерах).
• ToolStripButton
• ToolStripLabel
• ToolStripSplitButton
• ToolStripDropDownButton
• ToolStripSeparator
• ToolStripComboB o x
• ToolStripTextBox
• ToolStripProgressBar
Подобно другим элементам управления Windows Forms. ToolStrip поддер
живает встроенный реДаЕТОР. который позволяет быстро добавить стандарт
ные типы кнопок (File. Exit. Сору. Paste и т.д.), изменить поведение стыковки и
встроить To o lStrip в Too lStripC o ntainer (подробнее об этом чуть позже).
Возможности поддержки ToolStrip в режиме проектирования демонстрируются
на рис. 19.20.
L
Глt\gз 19, Соэдание ОКОtl с hoмощыQ System.,WlndG\ilS,Fo.rm.s 793
Впечатляет?
_ ~~tudic> ~~ templilt6
",-"":
~ ~:
"
~ ~ .~
-G::.'1
-"i~~
i j!f ." .~
-<=
-~
1\1
"
...
а int.eroo CodI! "* Windv= u.... Cйntrol CuslDm ~ited !nherited
f<><m Conlrol Form u....Cootr'"
~ ~ LJ Jj ~~:
~
~ .. t~", у}
.,.,'. tIJ
w ob Custom Componen! SQlo..~ D.~t xr-LFJe XМL Sd1<!n1. XSlT Fi~ КТМI..Page
COl1trol d.oss
Г-- ~--.
!_
_ __.-----____.__.__ _ ___ __ ------.0-.----
-
growt=ont,1C1)
-о
---- -- ---.-.--~ . ~.
-:""'" _~ ~
~ - .-- - . -.. -.- - - - - - -·-1
...!
дdd 11 CarиI J
L
Гла811 19. СоздаНl'Н~ (УКОН t ПОМОЩЬЮ 5ystem.WindDw,s.Forms 795
После этого ~Ы может~ отреДaRТИроватъ с-вои изображения с помощью окна
Colors и -комплекта И8струм;еuтав реДактОра изображений. Имен ПИEroграммы Б
.IfВ1JИЧШd, Щ>J; мощете Сi'fязаn; :Щ~. С типами ToolStripВuttQfJ с помощью СВОЙС'I'ва
Image в ОIЩе своЙств. J1Ш:JIе того nаБ вы сочтете внешний ВИД 'TaoLS,t rip удовле1'ВО
p~, обработa:i::vе сОбытие Clie;k для :каждОI'оэлемeIiТа ТОQrStriРВllttоп.
~o,.. СООТВIn'G'П'УЮЩI<Щ проrрaммньiЙ КОДJ<d€тода lпitiа li-zеСоmропепt () ДЛЯ
первого ТИIl::,I -тооlS11riрВuttоп (ВТ9рбй T001St.ripButto!\ вы:rnндиr почти та1-С же).
11
11 toolStripВuttonGrovFont
11
this . to.olS-t.riрВuttопGrоw!"QпJ:: . -Di$рlауStуlе
=
$yst'sm. W~п-д.ОW'З . f'сэrm;? 'Теоlst rip:L tеПlDisр1 a'yS't yl.e .Ша че;
this.too-1StrlрВutt'опGrоwFоrlt. Irna'-'Je =
( (system.Drawing. IJТ\$;ge)
(т~з(')итсе5. GetQbjeot. ("loоlSt:riрВuttQлGrоwFопt. Irпаgе") )) ;
thi s. tool StripButtanGrowFont. Lmаg,еТrаI1sраrелtсоlоr =
Sy3t6!11. Dr<J,wing. CO!J.OT _. Иаg;еn,tа;
U\i s .. tool S txipBut tQllGl'Q.wF~m t . Name = "too1St.ripBut tопGГQwFоn-t";
this. tooIStripButto nGro.wFont . Text = "·to o lS·tripBt1t to.n2" ,
this-. t,yolStYipButt~nGrow'F~')'n1i: . lL'ool 'ripTex-t = "Увеличить щриф'l'";
·this . .tQolstri-рВutt 9п.Gr0w F~ пt. Click t= new
S-y.stem. EventBandler (thiS . toolstripB~ttonGrowFcm.t_t l i сх);
замеч.анме. Обр.атите внимаitие на ТО,. что значеf1ие, прИСдаиваеl.40е свойстау Ttr.age типа
Tool$t rlpBut ton, ПОЛУ'-lается с помощ~ю метода GetObject (). Как будет ПОКЦЗЭIiО в сле·
дующей главе" этот метод исполЬ'Зуетс~ для' извлечеЮо1Я BCТPOetl~biX -ресурсов, ИСПОllьзуемых
КОмПОНОВОЧI1ЫМ блOlЮМ _
I
796 Часть IV. Программирование с помощью библиотек .NET
public MainWindow ()
(
this.too1StripTextBoxMessage.LostFocus
+= new ЕvепtНапd1еr(tОО1StriрТехtВохМезsаgе_LоstFосus);
Работа с ToolStr]pContainer
типы ToolStrip, если требуется. можно Н'астроитъ так, чтобы оliИ МОГЛИ ~cты
коваться
W
.
,_ _ ..' _ _ _ J
1
798 Часть IV. Программирова~lие с помощью библиотек .NEТ
r
РrОр"rhб ' rgJ
toolStripContainerl.Invalidate(true) ;
toolstripContainerl.Invalidate(true) ;
}
/ / Теперь ".!Iахрa.mивае'.l!сtl" JCОН'.I!еЙнер, а не форма!
private void ContentPanel_paint(object sender, PaintEventArgs е)
{
Graphics g = e.Graphics;
g.DrawString(toolStripTextBoxMessage.Text,
new Font ("Times New Roman", currFontSize),
Brushes.Black, 10, 60):
ОЧень интересно,...
Создание МD1-приложения
Чтобы заверпштъ крат:кое3I::IЩtомС1;'ВО с Windows FbП118. ·да.вЗЙТе обсудим ТО. как
настроить форму на работу в K8~recTBe родителъCJWI'О об1.екта ДШi ..любого числа
ДDчерJiИX O~OH (т.е, В дачес.т~е MDI-крнтеЩiера). МDl~прИлCiжеНШl дают nOlIЬЗ0ва~
телям .возможность oткpwвaтъ. множ~ство дочерi:mx OROH в рамках однorо и ТОТО же
LayoutMdi(МdiLayout.Cascade};
LayoutMdi(МdiLayout.TileVertical);
LayoutMdi(MdiLayout.TileHorizontal) ;
Application.Exit();
Резюме
Эта глава рассказывает об основах построения графического интерфейса с по
мощью типов. содержаш,ихся в пространстве имен System,Windows.Forms. Сначала
вам предлагается создать НеСКОлько приложений вручную. и В процессе этого вы
ясняется, что GUI-приложение. как минимум. должно иметь класс, производный
от Farm, и метод Main (). вызывающий Application.Run (),
в этой главе показано. KaI, строить меню верхнего уровня (а также всплываю
щие меню) и как обрабатывать события меню. Было также выяснено. как можно
расширить фyнRциональные возможности типа Form с помощью панелей инстру
ментов и строк состояния. В .NEТ 2.0 при создании таких элементов пользователь
ского интерфейса предлагается использовать MenuStrip. ToolStrip и StatusStrip.
а не типы MainMenu. ToolBar и StatusBar из . NEТ l.x (хотя эти. уже устаревuше
типы. тоже поддерживаются). В завершение главы бьmо продемонстрировано. как
с ПОМОЩЬЮ средств Windows Fопns можно создавать МDI-приложения.
rЛАВА 2'0
Визуализация
графических данных
средствами GDI+
Звмечание. Если вы профаммируете АЛЯ Web. то ме-*ете ПОДУМЗiЬ. что техно1ЮГVI'И 601+ вам не
ПРИГQДIiIТС;Я, ОднаКli! на самом деn6 эти техНОЛОГИИ' не ограНИLIИВаютi:;Я талыш тр<ЩIЩИQННЫМ'И
приложеf.tИ>ТМИ - они оказЬ!ваеiСЯ' исклюЧитеЛЫ:i.Q Ва>I<НЫМИ и ДЛ~ Web-при.nожен",~.
ческого образа.
L
'Глева 20. $изувлизация графических даl'tl1ЫI< (;JЭ8дсrвамloI GD1+ 805
Таблица 20.2. базовые ТИf.1Ы пространства имен .sy stE:;In .DrC!wi о ч
Тип Оm4сзиие
Bi t i1J ар ТИП, инкаПСУЛЩJУЮЩИЙ даныые изобрэжеlЧИ~ ( ... bmp 'Или каког.о-,о другого)
S'': U SI1 Qбъекты BrtiSfI ИСПОПЬ3,~ЮТСЯ для запопнения внутренних оБЛ(1.(;тeii1 гp~
BH'J she s фичеСКИ)I; форм. Rапример, tаJ(их~ак ПРЯМОУГ()Л'Ы,JИКИ. эллипсы И MNOГO
эоЦdВ i·U"Ь }!ГОЛh>Н~КИ
SY,5 t eJJ1.J3;r:u.s b~ O':
Te xtll:teBrus l'1
ВUffer9dGr aphics НОВЫЙ тип .NEТ 2.0. ~П5чиваКilщий графи ч еский буфер ДJПI ДВОЙНОЙ
буфер ~эацI1И. 1<оторая и"Споль~уется ДЛЯ уменьшения или полного ис
клюЧенvrя влияния эффВК1<J. М6i1Ь1ЩНИЯ-. возн\,;каlOщеrо при перерисовке
изображений
Co1or Типы Coio.t И Sу st'8mrL~ь LQ r-э оnределяlOТ РАД статических свойств. до
SystwlCole.rs ctym-ibIХ талько ДЛЯ Чтения и- исnо1l1,>зуемы x ЦЛR 110ЛУ'!ения НУ'жноrо цвета
при использовании рjjЗЛИЧНЬ~)( перьев и tщствй
lm",ge Тиl1 II'!I <;J;ge - это абстрактный оаЗОI!ЫЙ класс, fjеобходимый для nодцерж-
Im-а g еАnitпэtоr 1(11 фуI-Lкцион8лы-,ьIхx .80ЗМO.JКносrеИ типов Bit :map. I CDn И Со tsCir.
Тип I:maqеlilllШi9 Gor обеопечивает ВОЭМОЖIoJОСТЬ выол\;lени~'' цикла rlO
~Iабору Тl<lЛОЭ Тm а че из некртороFO заданного IIIнтервала
stri ngFOrmat ТИП. испольэуемыi1 для ИНlЩfТОVJlRЦИИ JЩЗ,JlИ Ч НЫ!! Х'арактерисtиJC размеще
НИА' текста !В!;lра8НИВд,),{ие. ПРОМЭ-ЖУЧ<1-1 между строкаМИ и Т. Д.)
перегруженных операторов.
Тип Point(F)
Первым утилитарным типом, о котором вам следует знать, является тип System.
Drawing.Point(F). В отличие от иллюстративных типов Point, создававшихся в
предыдуших главах, тип Point(F) GDI+ поддерживает целый ряд очень полезных
членов, вWnOчая следующие:
L
Глава 2а, Визуализаци.Я, грtJ.фическ.их деНfIЫil сред:ст~ами GDI-t 807
11 ИзиеиениеЗRa'lенив Х дmr pt2 ,
pt2.'X = 400.0;
Тип Rectangle(F)
Типы Rect а 09 le. пюдоБНt1 Poi nt, ОR:азъmаются полезными BU МНОГИХ приложе
~ (и осо'бе.f'ПJО EI GШ-приложеШ'illX). Oдrrnм ин наиболее полезных методов типа
Rec't..CJ ng le юз.rщетсв метод
CODtairJs (') . Этот метод ПО3ВОЛНе7' ВЫНСНИ1Ъ, нwюдитс:Я
ли данный тип 1'oi пt или RectaI1g1 е в раМках границ не.шiтороrо дрyrwо 'Объекта.
Пшtже в этой же главе вы увидите. :как испОльзовать ЭТОТ метод длн цроверпи 00-
IlЦДa.ю,IЯ 13 область (iШ-изЬбрюкеНИй. А лоха что рассмотрите сдедУ1ощиИ простОЙ
ПРI~мер.
Класс Region
Т:щI 'f{egion представляет ВJIYТреннюю часть, геометричешюй ф.иrур:ы, С учетом
;ЭТОI'О становится ЯС1'Ю, п{)че1о~У KOHCTPYJtТfJpbI класса Rеgiол требуют, чтобы вы
предШ,:тави"тrи им: 6а В,ХОД иеJCОТОРЫИ y~e еущ~ствУ"НJЩИЙ геометричеСRfIЙ шаблон,
Лр(:"дположим. НЩlример, ЧТICt вы создади прямоушдьюш размером J 00>< 1 00 пик
селей. Чтобlil получить досryп н в:нутренnей области пр.1:fМ:ОУГОЛЬНИКЭ. вы можете
H~CДТЬ следующее.
r
Класс Graphics
масс Sуstеm.Drаwiпg_Grарhiсs-это "вход" в функциональные возможности
визуализации GDI+. Этот класс не только представляет поверхность, на которой
вы хотите разместить изображение (например, поверхность формы, поверхность
элемента управления или область в памяти), но определяет также десятки членов,
Iшторые позволяют отображать тен.СТ. изображения (пиктограммы. точечные ри
сунки и т.д.) И самые разные геометрические формы. Частичный список членов
данного класса представлен в табл. 20.3.
Кроме ряда методов визуализации. класс Graphics определяет дополнительные
члены, позволяющие конфигурировать ~состояние" объента Graphics. С помощью
присвоения подходящих значений свойствам, показанным в табл. 20.4. вы можете
изменить текущие харюпеРИСТИl\И процесса визуализации.
l
Глава 20. ВИЗ)'tJ.ЛИ..з:щия графи'lВСКИХ дзitны~ средствами GDI+ 809
Таблица 20.3. Члеl~Ы ~ecca Graphics
Методы OnиС3lf"е
С.воЙс"ГН Описание
С:оmРОБit :!. h-gМпdе CBoCfcfВO .соmрюsit i DgMo.de задае-1 режим визуализации: либо ри~
Compo'si t i!lgQua,l..Lty СОВЭJ-IIЦ'j ПО8ерХ фона. Щ1бо соnряжение- G фОНОМ
I -rrt е.rр оlаtiiэпМоdе Указывает режИм интерrЮJlflцi1]А ДЗ>II'IЫХ меЖЩ' конеLIНЫМИ rочкз.ми
81 О Часть IV. Программирование с помощью библиотек .NEТ
Сеансы Paint
Наиболее общий способ получения объекта Grapr.ics заключается во взаимо
действии с событием Paint. Вспомните из предыдущей главы о том, что класс
Control определяет виртуальный метод с именем OnPaint (). Чтобы форма отобра
жала графические дa.IпIыe на своей поверхности. вы можете переопределить этот
метод и извлечь Qбъент Graphics из входного параметра
F'aintEventArgs. Для
примера создайте новое приложение Windows Forms с именем BasicPaintForm и
обновите полученный класс Form так. как предлагается ниже.
L
Глэвэ20. Визуализация графически)! Аанных средствами GDt+ 811
.любой ме-roд:. получаюIЦИй 'в RaчесТ8е первого параметра S'lstem ..Object. ~ в кц
чес:rne второто --P'ai пtЕ\i'.3лtАr gs. В npe.дположении Q '1'01.1. ч1'О вы обра60Тали со
бытие Pa.i:.o.t. (с ПОМОЩЬЮ И1-IС1'румеmов режима проектироиания: Visua! Studio 2005
или.в aj:ЮI'РамМНОМ ко,цб вручную). вы онова можете извn:ечь ОО)ъек'! Graphics из
-иостyna.ющегtJ на вход PaintEv·et1.t .Ar.9 S. Вот соот:ветСТВУЮЩИ!vl 06раэом модифИЦIII
РОВЭНliЫЙ nporpaNIМНЫЙ :КОД.
НеасщИСИМQ от -того. на;к вы Qтвечаете на событие Pa-ut., :следУет ю-mть. Чl"о. со
бытие Ра int ге;нер1'1'Руется: Bc.e~. KQrдa ОВifЮ С.dНOВИТС.8 ~". ВЫ. 80ЗМОЖНо..
знаете. 'ЧТо. OIffiO C''iJ}ifTae'l'CJ'j: ·грязщuм", еСЛИ пере-onpедел&еТC!l его. размер. oКI!ro (или
его часть] о:ткрьmаетси ~з-под ДРУТОТО' окна, или окно. сначала мИнимизируется.
а SjЭJ'ем ВQсстав;авли,ваетс.я:. Во все r:;лyч.aЯx, ROГД& требуетс.нперерисовка ф.ормы.
IШатформа.NЕТ гарщдирует, что обраб()"]'>ч}ш ооБЫ'DIЯ ~PaHt (JШИ пеРlюпредёлен
Н)'J.[Й метод ОnРа int (.) I будет вюзван автоматичесЮL
L
Глава 20, В'l1зуализащtfl rpаф»lчеСJ(И~ данных Gредствами GDI+ 81З
Эта лоrика отобраЖ<lет круг ,за uр(::делами обработ<nша Оп P'al n,t ( ) ., по очець,
ваЖl:1Q по}-IйМaТР. что l{()ГД~ въmОЛI;IЯетс;я обновление формы. все такие RРУГИ: ("J'и
РaIОТСЯ! Это разумно. UDСКОл.ьку соответствующая вИзуализация выIJlwLJlась.в
KQНTeRcтe событ!'lЯ Мощ,еDо!o>Jn. Значительно лучшим иОд.ход.ом нвллen:-JI создание
в обрабо'f<.nme t.'QБыия ,M0J.1seIJc>w11 новота тиna Poih'k который ,l10ба:вл.яется х ие
lюторай :внутр~щей колле1'СЦДИ lFJЩIРИМер. List<T>J., И только затем llыаЫWclетея
rii~al idate {}, Тогда Обраб0Т'1;IИКСdt3ытил Ра iDt может просто ~проити" пО IюЩIек
ции и neрерисощl.ТЬ R,ажд:ый 1'01 nt,
p'UЪ 1 i с ра.гt.i a...l c.1 "S'S НаiпFN-m ; 'F'orrn
{
11 ~СQ()J;&Ьз:у<е'1'СR ~ жранеВИR всех Po.int .
pIiiV;;J',t-е L.ist <Ь' сiп't.> myIJU; = new 'Li:оt <Р оirп > О:
P11bl :i c MainFQrro.()
{
/I Добaв.nеиие в ХОillЛ81щи:iD,
mу~'uз .Add (Dew PQ i n.t (е,Х , е.У))!
1 Щ7·аl± d,a't е ();
При т.аJФм подходе уже отобрamенные J~РУI'И будут о"та:вМ:Ь('5] Па Мё'С1"е. ПО"
СКОЛЫ')' графич:ес~ШJ Il]I3~ЭJmзац:ия Q6р~баТЫБае'l"СН 'в РЭlVlJl'<lJi! события Ра i.,ryt, На
ри(' . 20',1 пОказано оющ тестовото залуСJta этого ПРКJIожен:ия..
ЛриветGDI+
, ........: . • •
•
ИсхоДIOilЙ 1I.QД . пр.оеkТ BaslQPairitForm размещЕЖ 1;1' подка.т<ЩОге. соответ'Ствующвм главе 20_
J
r
!
тод Dispose () объекта Graphics. тогда как в других примерах зтого не делается.
Поскол:ьку тип Graptlics работает с самыми разными неуправляемыми ресурса
ми, имеет смысл освободить указанные ресурсы как можно быстрее с помощью
Dispase () (не дожидаясь. когда зто сделает сборщик мусора в процессе финали
зации). То же самое можно сказать о любом типе. поддерживающем интерфейс
IDispasable. При работе с объектами Graphics нужно придерживаться следую
щих правил .
• Если объект Graphics был создан вами непосредственно. после окончания
его использования его следует освободить .
Для того чтобы это стало более поRятны,' рассмотрите следующий обработчи]{
события Paint.
компонентами системы.
Однако, заметьте, Dispo se () не вызывается явно для объекта, который был по
лучен из поступающего на вход PaintEventArgs . Причина в том. что вы не созда
вали зтот объект непосредственно и поэтому не можете гарантировать . что другие
части программы не используют его. Очевидно, что при освобождении объекта, ис
пользуемого в другом месте программы, могут возникать проблемы.
,
l
rnaBa 20. ВI>I3Уалиэация rрафIil4!1СКI.\jt данны)( среДствами' GDI+ 815
в CIЦf3И С enшзам~. что если:вы забудете выЗв.-::nъ метод Di$РОЗ~ () ддя оРъеК
та, реали~ующеГ(i)· lDi's pos.a:bl€, BJIYr'pel-Ililiе ресурсы будут освобождены n032f(e,
при обработке объе1\та сборщmюм: муёора (см. главу 5). В Э'rо:м сМысле ос:аобожде
яие объе,кта img(;:r aphips, строro товорн. не является необхо1IИМЫМ. Так ЧТО, хота
явное освобощдение о{5ъсктов GDi+, созданных вами непосреДствеuно, дела.t:Т про
гl'эммный J(фД сове:ршеннее. мы с Baм;U. чтобы сделать п:римеры llpогр:LММНОГО шща
Бэтоii щаве боле.е В:Рq::П;rnми, не будем освобождать каждый ТИП ОО1+ вручную.
КООJЩJtШ1Т"cI.М.. Это удобно 1'оtда... когда вы -не XOT~Te вычислять рмещсниt't в сво
ем программном тооде ВрyчнJЮ (ВЫ nе обязanы это дедат.ь), НЩIpJilМер,е-.с.пи у вас
есть форма. ROH:Jpaн должна оставаться в грЭНШJ;ах 100)(100 шпti:::елеЙ. вы мошете
указать страничную координату (1 00*100), чтобы В'И3УaJЩ*Щl(IЯ ВblЛоJIFI.ЯШ;iСЬ 0']'-
носителыю точни (] 00*100). То:ща в своем базовом коде nЫCMOH~eTe просro указать
мировые J«(}ОР)il,инаl"ы (избежав. тем самым, необходимости вруч:нyIO ~ЮЬ
смещение).
1-IанОНец. есть nрuборн.ые l(o()pдUHamь~ (КОQРд.щ'fan!J J~ТРОЙСТва), Приборные
:координаты представляют результат прим:е.не1ЩЯ С'I"рa:IЩЧНЫХ :координат :к ори
(О, О}
х
на bepX1-Iеro и девого Края ющецт~кОй области формы. нак шшазано на рис. 20~3.
1/ д.'Мм.
l nc h ,
/I C'1'aR,!{apQ!l~ e~a' ДQJtyИеiWa (1/300 ~a) .
Dacu:m:en t,
/ j МИпnиме7.'р .
Mi l l irгre t~r
privat e 110i d мq. :i n Fс,Л'l";l_ Ра i о t {abj ec t s е пdет , Раi л t Еvе n tАТ <g$ е)
I
11 0wображевив Dpяиопo.nьни~а в ДIOЙМaX r а ив в пихсenих ..•
G r.арh1с э g = е. Graphics I
Ч . l"а gеUлi t = G.taphi CSLJf!it. Inё.'I1;
g .. Dr дwRес t адgl е {пе W P e l'1 (~Cc> l Gl r. Re dF 5 ), О, О, 100, 1 00);
j
818 Часть IV. Программирование с помощью библиотек .NET
Причина того. что здесь более 90% области нлиента формы занято темным
(нрасным) цветом. заключается в увазании пера "шириной' в 5 дюймов! Сам пря
I
моугольник теперь имеет размеры 1О0х 100 дюймов. и тот маленький светлый пря
моугольник. который вы видите на РИСyнRе в правом нижнем углу. является левым !
верхним углом большого внутреннего прямоугольника.
t
Изменение начала координат
Напомним. что при использовании координат и единиц измерения, предлага
емых по умолчанию. точка (О. О) находится в левом верхнем углу соответствую
щей области. Часто это и является именно тем, что требуется. но что делать. если
вам нужно поменять точку. относительно которой выполняется визуализация?
Предположим. например. что ваше приложение всегда должно (по какой-то при
чине) оставлять пустой полосу шириной в 100 пикселей вдоль границы области
r-слиента формы. Torдa вы должны гарантировать, чтобы все операции GDJ+ вы
полнялись в соответствующих пределах внутренней области ,
Один из подходов, который можно при этом использовать. заключается в добав
лении смещения вручную. Конечно, утомительно добавлять значения смещения к
каждой операции визуализации. Значительно удобнее (и проще) бьmо бы исполь
зовать свойство, которое. по сути, говорило бы следующее: "ХОТЯ я даю указание
отобразить прямоугольник с началом координат в точке (О. О). вы доткны исполь
зовать для начала координат точку (100.100)". Это должно сильно "упростить вам
жизнь", поскольку вы сможете увазать параметры размещеl-ШЯ без модификаций.
В рам.ках GDI+ вы можете увазать точку начала координат. установив значение
трансформации с помощью метода TranslateTransform () (класса Graphics), по
зволяющего указать страничные координаты, которые будут при меняться 1< вашим
оригинальным мировым координатам. например:
~,
.~..
11 Попучение
Color по известному имени.
Color myColor = Color.FromName ("Red");
Независимо от метода получения типа Color, с этим типом можно взаимодей
ствовать с помощью его '-иенов.
L
Глава 20. ВИЗV811i11зация графиче<;киJo: AaHH.bIX f:р~дС'твами G[lI~ 821
Кnacc CoJorDiaJog
Чтобы (jf5е(~Ilf'.Чит:ь К{)lreЧНОМ:У пользователю прилотения ВQЗМОЖR9СТЬ .IW;нфшу·
рирщщть тип ColoL ПРQСТРанство имен Sуs·tеIJ1..WindОW$.fОЛJ\S предлагает Brтpo
еБ.Н.bIЙ wщ.се диалогового oкna (' иМенем ColorDialo'g (рцс. 20.7) .
.~_Ii
_гггг •••
• I-ГГГ •••
•• г • • • • •
••••••••
••••••••
• •••• · t!Ч .г
,&nOtнorl.S_Jl/!lJТ~
гггггггг
гггггггг
:J
1
822 Часть IV. Программирование с помощью библиотек .NET
т
Исходный код. Проект ColorDlg размещен в подкаталоге, соответствующем главе 20.
Манипулирование шрифтами
Теперь давайте выясним, как можно программно манипулировать шрифтами.
тип System.Drawing.Font представляет шрифт. установленный на машине поль
зователя. ТИпы шрифта могут определяться с помощью любого числа перегружен
ных конструкторов. Вот вам несколько примеров.
11 Соз~ание
Fon t с за.цаниыми именем типа ,И размером.
Font f new Font("Times New Roman", 12);
=
11 Соs~ание Font с за,цаННJolИИ именем типа, размером И начертанием.
Font f2
= new Font("WingDings", 50, FontStyle.Bo1 d I FontStyle.Under1 ine);
Член Описание
Возвращает метрику I-/aдcтpo"ll'loro элемею-а дЛЯ <ИJ6НОВ данного
сgмейстgiЗ
Заметьте, что указанные члены типа Font Famil y возвращают значения с ис
пользованием в качестве единицы измерения Gr aph i c s lJn i t . t'o int (а не P i x el).
что соответствует 1/72 дюйма. Вы можете преобраз овать эти значения в те еди
Ioщы. которые вам подходят лучще всего .
, ,_ _ .J
Чтобы начать реализацию ПРИЛQжеmш. добавьте 'в форму член Timer (с именем
s,wellТUfler). ссх:рон:у (s,t 1: Fоп tD'ace) для представлеl-lИЛ теиущ.еrо н:щванщ:r гарниту
ры .IПpИ'фта и 1~елое число (swell Va l U.e) ДЛЯ ПРе'дставле1:nЩ веJtИЧИНЪ! и:орректиров-
1m для размера шрифта . В он'не прое"тированйл форМhI сконфигурируите Ti,m,e r
ТаЕ, чтобы он генерировал соБЫТ1re T.ick На)Кдые 100 МИЛ:1:Щсе.кунд.
риыl c MaifjForm ( )
{
I Л.i t i a l i z е(lОl,lРЬЛtП t () ;
Ва с kCo,l о т "" Со} оу .,8 0 0" y,dew;
С'е пt,еу"ТоS с r е е п () ;
11 КоифигурацИR таймера.
swel lTlme:r .EnаЫед =tr це .;
s w,el LTime r. I п t еr.таl = 100,;
.s.we llTlme r . Ti.ck += пew Еvе.пct И а:п,dlеr (swtoil Timer Ti ck ) ;
Теперь, когда с каждым циклом Ti mer обновляются верхние 100 пикселей об
ласти клиента, нужно найти что-нибудь подходящее для визуализации. В обра
БОТЧИRе Paint формы создайте объект Font на основе выбранной пользователем
гарнитуры шрифта (она выбирается с помощью соответствующего пункта меню)
и текущего значения swellValue (оно задается таймером Timer). Настроив объект
Font, поместите сообщение в центр соответствующего ПРЯМQУГОJlьника.
Обработч:ик Click для пункта меню Рост? будет использоваться для запуСl\.а и
останОВRИ процесса увеличения текста (т.е. ДЛЯ разрешения и ОТlUIЮчения анима
дин) . Здесь используйте свойСТВО Enabled объеlпа Timer тю{, нак показано ниже .
private void swe l l Too l S tripMenll Item_Click( o bject s e nder, Even t Args е)
{
swel lTimer .En abled = r swe l l T imer .E n abl e d;
L
Гл.ава 20, ВиэуаJ1иза~я графичес~их даннщ Gредатвами GDI+ 827
Клаос FontDi'alog
КaIt вы можете догццъma:IЪСЯ. существует и класс диа.лаroВQГО окна для :нас~ой
ки шрифтов (Fof1tDialoq). B~ этОго окна .Dохаэ!аН на lJЙ{;. 20.11.
}
ргivа.tе void маiг,Р-о.r:m_РeJ.nt'( оЬjе,сt $~det , РаiПI;.Еvепtl\гg-s е)
j
Grapr,ics g = e.Grapbic~'I
g.Dr""wstгi:tJg("ПРОЕ~РJ',:.д ... ", cu.rrF{)nt, Бrцзhеs.Вlасk, О, О) i
830 Часть IV. Программирование с помощью библиотек .NEТ
Классы Описание
Свойства
D:as:hl'.at te! n ЧИТClет или уаraнавливает массив пальэоват-еЛЬСКОk\ маски доя риr.аваНИR
преР.ЫВИСТI>I)( ЛИliиJi1 . Соответствующие "тире " i:КJ111ДЫВЭЮТСЯ из Ge.гментов
лиНИЙ
DashQff ;;:et ЧИ'ТaRТ или устанавливает расстояние от начала ЛИНkИ ДО начала шаблона
прерывиетой лt.l1НИИ
llоr.шнте о ТОМ. Что gnоба.во'К ~ nщy Р-еn Б GDI~· предЛ.агаетС'я ko-ллеКЦИJi р'е rч~.
Использу.я ряд статических ~оЙст.в. вы мощете измеч:ь Н3 этой коллеКЦJm объ~
Реп (йЛИ tI}'ЖН'ЫЙ !IВeT) ~н:a лету", не создавая ПО.1Ibl!ователрсКИЙ 'Тип РеП ВруЧНУЮ.
ОДНШ;:О следу~ з.нщъ. ч:tо воэв-ращаеl\o,IbJ.Й: цри этом ТИП Реп Вl,::егда имееr ШИРЩ:I)'.
равяуlO 1.
Если ВаМ поющобятся: Jt<tКие-тр ;ш,зотичеекие перъя. вы ДОЛЖJ!Ы создать тип
Рео вручную. ПреДОМ'авив вам :';lТy И1'lформацид>, я теперь моту Пf'реЙТ1! Ji: цо
строению примеро'f! геОМt"Трических изображ.енИЙ с Щ>МОЩЬ(О пр@стыlx типов РеП.
Предположим. Ч:'tо у нас , есть rnавный 06ъеI(Т р'ох-m, сп@~ный отвеЧаТЬ на запРD~Ы
визуаJJJlзaцrol. Реализация ответа вьrrляwп так.
Й, ВЫ, там,
fl8sep.xyl. Я 83f11
привет передаю.
КОНЦЬ! ЛИНИЙ
Если paCCMOТp~ь ВЫВОД предьЩу'Ще'ГО примера. }JbI Должны заметить. что на
ча.lIО 1i RОЯ6r...:r; RШRДОЙ дmuщ там оформлен Bno.т"IНe стю-!дартrю - ЛИНИЯ "С'реааетсн"
лод уt·лом 90 R ее tronpа.вленИlO. НО. ИСПШIЬЗУИ перечень LiдеСар. вы имеете .воз
й
Square
ltound
NoAncl1cn
Squaш\ncЬоr . . .- - - - -•••
RoundAncl1or . . . .- - - -• • •
I>WnondAncl!orAe-----е.
• ,
AncЬсrМак
Сшtоm
Нщхеюоъ, щ.l СQГJЩ~И1'есь, что .это Dpшroжение поч.ти ИДе1-JТИЧНQ еоздаНflОЙ Bыme
программе Сu' э.tоrnРеnАрр. но иcnолъаует методы Pi.llXXX!) и типы SolldBrush
вместо перьев.и соответствую.щнм им :методов Dra wXXX О. на рис . 20.14 ПОlЩЗЗН
соотве~твующий вы:вОд.
1
836 Часть IV. Программирование с помощью библиотек .NEТ
r
~,. SolidB'lJShдpp GJI5I!'8J
-=t!1, вы, ГJr,'
H-rс,I:IJ '11 r;~ Б-1r,1
П! 111f I-'T 11Г'llt Д 1М J
Работа с HatchBrush
в пространстве имен Sуstеш.Drаwiпg.Drаwiпg2D определен производный от
Brush тип с именем HatchBrush. Этот тип позволяет закрасить регион. используя
один из (очень большого) набора встроенных видов узоров. представленных переч
нем Hatc]-lStyle. Вот часть соответствующего списка имен.
в iЖне ;Вывода будут noкаээны <iaIюШlенйые овалы для первых пяти значений
ВЦЦОБ штрИхОВRИ (рис. 20.15).
Работа с TextureBrus.h
тип ТёхturеВ.rush П()ЭВоJiяе:t СВJiэать е дистыо точечное изображенце. ч:'ГОбы
затем :аспоm.зо:ватъ ее Б операциях ЭaJ<Рашиванwя. Чуть поаже будет подробно об
суждаться класс lтаче (изображение) GD1+. ТИРУ Te.xtureB:tl)sh предщ:тавл.я;ется
CChlJ1Кa на lщаqе. ~исполъэуемая этим ТИПОМ в те"lеl-Цfе всего цикла его сущ~ство
Ваш производный от Form ЮIасс должен подцерживать два члена типа Brush.
которым присваиваетсв: tfовый объект TextureBrush в конструкторе. Обратите
внимание на то, что конструктору типа TextureBrl1sh требуется предоставить на
вход тип. производный от Image.
Замечание. Файлы *. Ьтр, которые используются в этом примере, ДОЛЖНЫ находиться в той же
папке, где находится само приложение (или должны быть "жестко" указаны пути, по которым
эти и.зображения можно найти). Соответствующая проблема будет обсуждаться в этой главе
чуть позже.
Теперь. когда у вас есть два типа TextureBrush, способные выполнить визуали
зацию. создать обработчик события Paint очень просто.
Работа с LinearGradJen'tBrush
П()('П~ДНИМ из рассматри;вз.емых :в ЭТОМ разделе 1\ипоа будет тиП L i nе а у
G:r:.ad1errtHruSb. ~О"fОрЫЙ МОЖЦО !tСПОЛМОВатъ тогда. 1I:otAa ,нужно смешать два цве
та в гр~иентной аахрасне. Работать с этим :rипом так же просто. каж и е OCT3дq
НЫМЙ тнпами КИСТИ. ВащцыМi моментом здесь JiВл-ается ТО, ЧТО при еоэда'Н;Ии
Linеа:tGr.зdlеI1tвruэh Jl}'ЖНО указать пару пmов Со10Т и значеНие для нацравде
nия смепщвюшя из п~реЧWJ L,inearGradientМ0de.
Holi.zOMaI
VtJtjcal
FOIWUdDi.agonaI
Визуализация изображений
R этому моменту вы знаете, как работать с тремя из четырех главных типов
GDI+: шрифтами, перыrми и кистями. Заключительным типом, который мы с вами
рассмотрим в этой главе, будет класс
Image (изображение) и связанные с ним под
типы. Абстрактный тип System.Drawing.Image определяет ряд методов и свойств,
хранящих различную информацию о том изображении, которое этот тип представ
ляет. Например. для представления размеров изображения класс Image предлагает
свойства Widtl1. Height и Size. Другие свойства позволяют получить доступ к пали
тре изображения. Описания базовых членов класса Image цриведенът в табл. 20.8.
Члены Описание
FromFile () Статический метод, создающий объект Image из указанного файла
FromStream () Статический метод, создающий объект Image из указанного ло
тока данных
3амечанмв. Файлы '* .l;,mp, K.Dl'OpbIe ИСПQIlb;:l}чоmя s зтом примере, должны нахо,циться в тОЙ же
папке, где находится оамо ПРИЛОЖfJние (И'nИ' доJ'lж~ы Быь"жестко"' укззаны пути" па которым
эл., изображения MOIКNO найти), СоответсТзующая праблемв будет оБСУждаться в той таве
'1VТb позже,
ИСХОДныi'l код. Проеl\'Т Basiclmag~ J;1азмещ~н в' ПОДIG3'Тё!Логе, соответствующем главе 20.
842 Часть IV. Программирование с помощью библиотек .NEТ
L
Глава 20, ВизуaftиэаЦl111 графJ,1чесжих д'f.ЩНJ.IХ t;редстваМfi GDJ :t 853
1
r
854 Часть IV. fТрограммирование с помощью библиотек .NET
, МАNIПSТ Г-ilБl!'Xl
l'i1d l'i1d ~x!
.uer 0:0: О: о
}
.nr~source public resxform.resources
{
/1 Offset: RXO'•• OOOO Length: DИОО'.1497
}
.module Program.exe
11 НUID; {C2C07EE1-1D18-4F78-9C6A-1082FF8C45EE}
..11 _ ............ _ _ ... п . . 41'1" о...а."аА
.(
Работа с ResourceWriter
в предыдущем примере мы использовали тип ResXEe so urceWriter, qтобы сге
нерировать XМL-файл. содержащий пары имен и значений для каждого ресурса
приложения. Полученный в результате файл * . resx бьm затем обработан ути
литой resgen.exe. Наконец, с помощью флага Iresource компилятора С# файл
*. тез о итсе з был встроен в компоновочный блок. Но дело в том. что создавать
файл *. r е s х совсем не обязательно (хотя наличие ХМL-представления ресурсов
может оказаться полезным, поскольку оно вполне пригодно для анализа). Если вам
не нужен файл *.resx. вы можете использовать тип ResourceWriter. с помощью
которото двоичный файл *. r e s ource s можно создать непосредственно .
{~ ~ 1)
~=-~~'~~~~:~=:;;~;/(1~б~} ~ ,-~.~
'". ;fJ!J~~
'i; ~ """"~
d ; ::Jj 'k~tln"'~
;,t;i ~ F'ormi,J3.
~""""t.~...,.
"Ы.., •
-,1) P' ;>gl·.om.",-
1
856 Часть IV. Программирование с помощью библиотек .NET
~: @J ~
~!
Рис. 20.28. Добавление нового CTPOI(OBOro ресурса с помощью редактора файлов *. resx
Рис. 20.29. Добавление нового ресурса * .Ьтр с ПОМОЩЬЮ редактора файлов * .resx
Главз 20, Виз-уа'ЛИ:<J,ЩIo1Я граф\'\'I6СХИХ данных Gредст~ами GDI+ 857
После этorо ВЫ оБIIаРУЖИ1'е. что файл "'. Ьтр скопирован в каТ<ЦlЩ' вашето npи
J10жения. Выбрав nИl<тограмму happ yDude в редawroре .... res~ и J!сцqJlljЭ-У,я воз
МОЖНОСТИ свойства P€ rsi stenICe. МОЖНО пе:гребовать. чтобы Д8.ЩiО(t изобрзжщmе
было непосредственно встроено в Кa:t\iШOНОВОЧJIЫЙ блОlt" а не ЗМ$ащ)сь ссылRй
на внешний файл (рис . 20.30).
(' , ~ ''''~" .~
· рц - t!OlК:l!
~, wr.. m..r iIw. _tllClltжided",~.
~=<м~... srIe6111!1!1_CIIIVe,
u.ы <""",.ао; тl'llil!ll ",1In""""~ onM
Тедерь OКEJO SOIution ExplOrer предЛщ-ает новую папку ПОД названием Resource$"
1WTopaн СQдержит !!се Э.ТЩМt"-,Нт~, :встроенные :в .компоновочный блок. Легко ЦОl'а
датьея, что при О'I"КpWТди ресурса Vjsua] stud10 2005 зaлycJCЭ.ет СdОТВетствyюtU;ИЙ
редактор. В ЩОРОМ случае, еi;ши вы теперь СЕомпйлируете свое приложение . ук.а
Зaнщ,J.е Ba:IOl Стр([)lfй ]f ~зображение БJAyт встроенЫ .в компоновочный блок.
'J
0·*
f:~"*•..".."=,, '_""'I'()<.._~·.:i;.;;-""".:c"-~O' I I
,
I
_________'..J
1'140" 20.31, Обflовленн~й и.нтерфеЙс пользоеаТЩ1Я
858 Часть IV. Программирование с помощью библиотек .NEТ
Резюме
Аббревиатура GDI+ используется для обозначения ряда связанных пространств
имен .NEТ, используемых для визуализации графических образов на поверхности
производных от Control типов. Значительная часть этой главы была посвящена
выяснению того, как работать с базовыми объектными типами GDI+ - цветами,
шрифтами. графическими изображениями, перьлми и кистями, используемь1МИ в
совокупности с ~всемогущимН типом Graphics. В процесс е обсуждения были рас
смотрены и неIшторые другие возможности GDI+. такие как проверка попадания
указателя мьшш в заданную область окна и перетаскивание изображений.
Б завершение главы был рассмотрен новый формат ресурсов .NEТ. Как выяс
пилось. файл * . resx определяет ресурсы в виде XМL с помощью пар имен и зна
чений. ЭТОТ файл можно обработать с помощью утилиты resgen.exe, "Чтобы при
вести его к двоичному формату I*.resources) и затем встроить соответствующие
ресурсы в компоновочный блок. Наконец, тип ResourceManager обеспечивает про
стой способ протраммного извлечения встроенных ресурсов во время выполнения
rrриложения:.
ГЛАВА 21
Использование
элементов управления
Windows Forms
Замечание. В Windows Forms предлагается целый ряд элементов упрзвления (DataGridVi ew,
BindingSource и т.Д.), позс!,!оляющих отображать содержимое реляционных баз AaHHI;Jlx.
Некоторые из этих элементов управления БУАУТ рассмотрены в главе 22 при обсуждении ADO.NEТ.
pub,1i:c MaiпWindow ()
{
11 КО~~rv.Pаци. формы.
th.is. ТЭхt = "П:рО'С"l1ы.е элементы управдеН14Я:";
t.hi.Б.!оН dth = ЗА С;
thj Б. Height. = 20'0.;
CenterToScreen();
class Program
{
рцЬНс stat;ic voiGi Main (striЩ1[J ·a·J rgs/
{
AppT[-са,t10n. Еl.in (Qew ~1ainWindQw ()) ;
862 Часть IV. Программирование с помощью библиотек .NET
ок
Тип Control.ControlCollection
Процедура добавлеЮ1:Я нового элемента в форму исключительно проста. но
свойство Controls требует дополнительного обсуждения. Это свойство возвращает
ссылиу на вложенный Imacc с именем ControlCollection, определенный в рам
иах класса Control. Вложенный тип ControlCollection содержит все элементы
управления, помещенныIe в данную форму. Вы можете получить ссылку на эry кол
лекцию. чтобы "рассмотреть список" дочерних элементов формы.
Член Описание
Замечание. Напом~м, что окно С8QЙста~ ее'ли щеЛКНУIb в нем на кнопr.:в ' с ли.ктarраммtiЙ мол·нии.
позволя~т обработаТЪ ' GОбытия. элемента управления. НужМо 8ыбрать элеМЕ!1П \13 раоiфЫВ~IOЩ~"
гося СП'ИСl<lа И указать ИМ\1 метода, IЮТОРЫЙ ДОЛЖefl вЬ!эыват!>Оя дnя интересующm вас событии
(<<ли просто выполtнп.Ь дзой'ной щелчок на имени события, 'Побы сгенериро.аOlТЬ рбрабРТ'lика
соl'Jl>ПиЯ с ItfMeHeM, npeдnaгaeMblM ПО WМО/1яаниlO).
Добшщге в' оКiЮ проеlБИрОВашш формыl типЫ TextBdz (тeltCTOBoe оюю) д еи t tOrt
(юIоnна). Обратите внимание на ТО, что при измененви положения элеме.нтаynpа,в
леRВН в 01:Ще праектирова..вик формы V1sua] Studio 2005 преДп:агаlОТСп визуалЬm;rе
FЩДС1ШЗIЦ~. Raсающиес.н размещения и выравнива.нин Э'I'ого ЭllеМ€II1'э. (рис" 21.2),
После р~:змe:iЦениff Butt,()!'! и Te~ tbo)( в окне проеlцированил формы рассмо
трите щ~ограмм:ный код. crенерированныйв метоце 111 i't ia 1.1 z.еСоmрОQедt (). Вы
обlla.~те, что соответствующие типы aItI'Oматически были создады с ПОМОЩblO
леw и добавлены в RОЛЛeJЩпю, СоntrюlСаllесtiоn ф0рмы (В дополцеJЩе кустанов-
1(Ш>f. Щ)Т'ОРPl:е вы, воэмоЖЕю, добtlВйли (t помощью OКRa свойств).
// МainWindow
//
this.Controls.Add(this.txtMyTextBox);
this.Controls.Add(this.btnMyButton) ;
Как видите, такие инструменты, как Visual Studio 2005, во многом избавляют
вас от необходимости вводить программный код вручную (возможно, иэбавляя и от
боли в пальцах). Итак, в результате ваших действий в окне проек'Тирования формы
среда разработки автоматически модифицирует InitializeComponent (). Но вы
также можете конфигурировать элементы управления и непосредственно в про
граммном коде (в конструкторах. обработчиках событий. вспомогательных функ
циях и т.д.), поскольку задачей InitializeComponent () является создание началь
ного состояния элементов интерфейса. Тем не менее. если вы хотите упростить
себе жизнь, позвольте Visual Studio 2005 поддерживать Ini tial i zeComponent ()
автоматически. поскольку средства проектирования формы могут проигнориро
вать или переписать изменения. сделанные вами в рамках этого метода.
• Button (кнопка):
Глава 21, Ис'МОльз.о,вани(! эnемсюов' УПР!iвления W!11<ШWS Forms 8б5
• Cher.J k.edl ,iE',:t BOx (окна отмеч:аfМЩ'О СПИCIiа). Li stЕю.к fliШНО СПНCRэ ) Й CdJr.boBox
(номбини-роваНRО(' ОНН{»),
Э'леме"т Label
Элемент управления ы Ье 1 (на:ллись) можt:т содержатъ информацию. до ступную
Т'ОJlЫЮ ДolJfJ ЧтеНИЯ (текст ЙJlИ: йзоeiрэжев:и:е). Щ!.1Ipимер. для i'DrQ, Ч'l'обы пояснить
1;Iощ,эова:геmо РОШ7 и возмоJКности И(;DОЛЫЮБани,Я" ост.альных элементов ynравле.·
Замечание. Порядок переходов по табуляции подробнее будет обсуждаться позже, а пока чтО ДО
стаТОЧliО заметить, что порядок данного элемента управпения при переходэх по клавише табу
ляции устанавливается с помощью Свойства TabIndex. По УМОЛ"lанию значение TabIndex
элемента управления соответствует порядку, в котором элементы добавлялись в окно проек
тирования формы. Поэтому, если вы сначала добавите Label, а эатем
- Textbox, то для
Labe 1 значение TabIndex будет установлено равным О, а для Textbox - равным 1.
I
[ _______~______ ~ ______.1
i
Элемент TextBox
В отличие от элемента управления Labe1, элемент управления TextBox (тек
стовое окно) обычно не является достуШiЫМ толы-ш для чтения (хотя его можно
сделать таким, если установить для свойства ReadOnly эначение true) и часто
используется как раз для того. чтобы позволить пользователю ввести текстовые
данные ЩIя обработки. тип TextBox можно настроить на подцержку одной строки
текста ИЛИ множества строк. его можно настроить на маскировку вводимых сим
S;;;roJ.l Ва::: s Читает или задает ЭНliЧ6Ни.в. указывающее необх.одимость Н,аличИf!. по
лос I1РОКРУТК\1 в Эflеме1Jlте управления 'I'extBo~, допускающем МflОГО
СТРО4НЫЙ ввод
Т-еж tAl ign Читае-т или задает .значвн-ие.• соответствующее DДtJОМУ ~З .значении
пере41-1Я HorizontalAlignw.erlt. и указывающее npввила еыравниаа
НИR i'sKcra в ЭЛ6ме~lте 'У11равления TecXtBo)$
/1 txti'&&sword,
/1
this _txt'P" $SW.Qrd. PasswordOl'iiJ.'r == ,
t '1:' •
JI txtмul ti1ine
//
thi$_t>{t.М!jJlt.i]'if1~.Мi.Jl:til-Lnе = true;
01'is. tKt1'1ul t i l ifle. 8cyollВ.ay" =
.sgs-l.em.Win(lоws ,УОТmБ. ScrollBa:r:S. Vecti cal"
.-,
1/tx.tUpperCaвe
11
O'\i в. t.xt!JpperCase. Cha:raaterCas'ing =
S,ys t.EUl1 . Nindo:we. Forrn&. Characterc:as1ng: _Оррет;
}
868 Часть IV. Программироваliие С помощью библиотек .NET
Г=Показать AaH;:i;J
..
ДШV~fI!i!I~а..
/~~.Н!)IJ3"~,
~';'сtWi.ItI~~1JQ~,"IJ'Щ~'
I!: .... "t~c." ~._T
~~~ib1trJI.'
~...,.~: .r~~III>_
ЭJ1е~еtП Mas.kedТext,Box
:в .NEт2.1'11 I1РЩJlТlагnетсн "Тш<ЯН: ~{роеанноете1iСТrл!об QRНО.lюtорое ЛQ3Щ1.~·'
.
ет 'Зaдa,n IЮющцоватt"'яhИОСn" С'И,иВОIТЮВ. ДQrrycшМ}'1Q ]J,.'r1Л I1Icр!ЮUiТ.ия буфер.ом 1ЩQД:;l
{ато 'М61WJtI' m'>tlЪ 'fltiM~P ёОЩiram.иоPi СТрахОВКИ, lелефoнnый lfOM<:P 'С 14;ijJtOM рerIЩ
на. IЮЧХОmJИ (Шдrotl21ifЛFr ЧТО-'I" $yr:gfi~. J'vI.a(,'RQ!,. с "Оl'О):JaЙ прdВ,Э1j()ДИ'te.R' "'Рa:JПIetf0е
(oon ~aeтcH :шй.БJi!l!)ft{).м' иJbl э·ыра.."ItImUPМ Шld(Щ. COMaeт~H € UОМОЩlbЮ специ
;ВЛf,ю"tx 'Марк!;;'ров. ветрееш-J!Ы1'К в- ('трощ,в~ лпrерan. tJОЗД8.li1:l0:е энач~~r: въrpаже
юш. J!i13:CRi% ~амс:я ®СiЙСТВ:У l'!ct~k. В ·wБJi. 21 .3 JЩ)ОтC;fl ОIШ!C'.а:ци,л .пеJ(JJ1'OV~.lX
м.аСDЧЮillX маrл{.еров.
Марк.ер
.
f1реД;QJ:SБПЯe:v с,ИМООl1.:цен~ж~оiiе4l~нkI!Libl
Э"W!Jjllrt}1~, СiI'М&.пl!Ol~ д0л~"г'1мы8. Af\Я Y\bYJмьзовЗlil4st I! T~II1:~. Иа ·s k.eа.Т9'Х.~_.вQХ, 'fle !mOJ'Jfle t(\~
.(jЧ-~f!fсtevю' С~~(jКСИС)l ~r'r'.rт!j(pl'f+,l~ '~ыра*е>iИrt,. )(OT~ ,NEi Jl.t flpeMar:.IeТ "'~6~arr;O;Нl:I\e f\[,IQ"
J,7r1"~НЮВi!I ~1..reE! дm;i i"a:f'i(rrbI aD tJт~!3P'ТflЫMM ,)J"t)JJiя'р1'iЫ'МИ Й.t;jРа.>м!",~1Я.ми· (!П(l ПfЮстр~а
'ИМе", !i у ~tБJfJ ;TE:~ ·t , Р,Е .g:!1 1аr'Е~р1.->;J~5I si ЩI$ н Sув't ~ 'i!!,.~'еЬ. . ~ g·ц lа J:r~рrэ~ 5icns )"
TWI' jt1a$:~RJ:.tB,D;Jj, иtrf!jjяю~t GIMfl:all'.c,(C. ВНЭ!Jн:irr.t-iРJмl\i СI4~I'!1i~СIolС~ .::ФSМiilЮm! 1f\раnЛ:etI~
GQM в \t&),
870 Часть IV. Программирование с помощью библиотек .NET
еж i[ С;ancel
Чтобы гарантировать, что эта ошибка не будет отображаться при вводе пользо
вателем корректные данные. обработайте событие KeyDown ДЛЯ MaskedTextBox и
ГlfflВВ 2"1,. ИсполЬзование ЗJtемеtlтов уnра8леНИ!l' W i l)dо,WS FOHn'~ 871
pt".amblyihe в ОбрабОТЧИRе. еьБыl1я в"осстЭШ)влени:е эагОЛОIЦ,(а формы 1'( значению,
I1:p1ШНТому по УМШlча:ниlO,
Элемент Button
8адачей типа Sуstеm.Wiпdоw.s.FDrrns.В1.1ttоп ЯВJще.тся "'ГРЩlспрртировка" JШ
формаций о вЫбаре пользо:ватeJIЯ. обычно 11 ответ на ЩeJI'IОR К!i(i)Пl:tи мыIии }ии на
Ж3.Т:i1е RJlавиши ПОЛЬЗ0вател~м. Itласс В1.1ttол (iCНonкa) пo.тryчается нецосредственпо
из абстрактноrо 'ТИпа Е1.itt ОriБаsЕ'. об.еспечивающего ряд :кшочевых во:зможпостcit
поведения для всех производны.х типов (таких. J(aJ\ С ЬесКЬо к . R ,aIjiot;llJ,t,tOI'l п
вu ttоп). В табл. 21.4 о:п:исанbI не1'(оторы:е базовые свойства Butt'o nBase.
Свойство OnИGaние
СВОЙСТВО Т' ехtl'.ligл тиПа ButtQ[,) Base СИЛЬно упрощает задачу ПОЗИЦИОЩiро
ванин соответствующ!::го текста. Чтобы позициоnнр.овать тенет JЩ nOBep~ocт.PJ
B'u tt..o n , ИСПОЛЬЗуЙТе значеl'fiiп! перечня соп tедtАlig tJ.m Н,t fопределеmюго в цро
сТранст:ве имен Sy,g-tеТn.DI С!wiпg). Повже вы yвидl'IТe. ЧтО этот же перечень MO~P
иCrюЛ&зоватъ и при размещении на пов~ры-щсти Bu.ttcНl изображеЮUl.
public MainWindow()
{
IпitiаlizеСоmропепt() ;
СепtеrТоSсrееn() ;
l
Гnава 2:1 , ИСПQJIЬЗ0вание элементов управления Windows Foгms 873
1/ Чтение Te~гo sначекия; п~е"lUit.
C'.lr.f tUi gn:rrier, t =
(ContentAl igI1mе л t· ) Еrшщ. Раrзе(сurr~'\.lig.rщщtIt .Get Туре ()',
vaI ues. Ge't Va 1 u iЭ (f~1J.I f:'БгJПЩР~S) . То:>!: ring (J ) ;
t{;?i {~~!~ . -" .~,, ' > . - ," ~~, :' ,~: ... ~ ,,' >1-·ч· ,,:
k
,
~ : '." • "", ..... ' 1'!~""_J'" ....
;:~':;:~,:"~~, ,~й,. ~~:' ~, _' '"~_ ' ·~iJ~~ >~. {~~ .~~:,:;-:~~~~.:~"
' ,; . ' , .-'.
.
.
1
874 Часть IV. Программирование с ПОМОЩЬЮ библиотек .NET
Свойство Описание
Tl1reeSt ate Индикатор поддержки в CheckBox не двух, а трех состояний выбора (в соот
ветствии с перечнем CheckS tate)
~" 3eA_I&~;~-'_~
.u-",~_!II.~$~
1,~bl·"lrotТ!'.~a1Ii. 1fJ.111р~К-""
~M"i31of.:r'ProQ~I.\eil?
/! Chе!бjtFl00r1kt'$
j/
l.;b"i./i. ciьfШ'·'.FIО6tМа:J; в, N&!l~e = "":c·n-eckFill.::· :t!~t.$";
t",r,.;1 э • с11i::.с:k:П Du.r!'}a L1i> ., Tab,rp:dtox ~ о"
·tTH:t;.\, cll!:!,с1d!'lО"'~Ма.tэ ,'Тe~!;: = ~ ·Э"iliJа сныеl!."!'-И~Р.ll':КИ ц:п~ мэшины";
ilii s _C~u tn,~ ]..s . Ма (и~1:!: .~.f.Le~ k,FI1щх-меt.S'J:
J
8aTe~ ду.itiЩ'У' C-В;ОЕфmyрп:рова-r:ь 5.rc'l'JyE.D'x и СQД(jрm:.аш.и~1{:В nell'f 'J'ln;п.J:
Fi,adiaВot.te<n. Чтобы pa,1М~пI!mТъ элемент jЩJi1'i1J1t"f.Шfi В PaмRax G.ti:il't!f'B'O,x:. ~
ltP~IiWtr;'=~' .э.ыm.otСН'Г В}f.Оm:It'JЩШO t.алt r~i18' ~GrО1.гр~[J>Х IТQЧIiCi)ТaJ~ $"."щ:l~ ~;Ы Ai.1-
6~ эJrel',1евтоы1 }'I1:;Р,;i nЛСЁШЯ :в :в:оШI;ШЮ'.(йЮ С G[1! r: ;:01 s формы). "{'РoQы [NJЩ'"1о, Q1'T}1-
a:fЩI!:) ипrep~, :ш:.'lJOIi&эуil~(J}ШО свойств ~ :щцaiiin: обра.60Т.fi3' С()6ыnrй ЕI1 ke<-l' jf
L~ve lPUJ ~~a .Gr.o llpjjk~J!." 1tAIi. rtt'mазш1О ~mже.
/I~c~
It
tl!liЗ'. r:adi·!JiR:eli!..N,iillIl1;< = Ura(;il.Q.F.-эd" :,
UJi,s ., !:adtL~d. .. s,::il.?;@ =r.ew :1:V5'U!m.D:r:'.а:,,'1IiJСj .Э,'j:?е!~4. 23)'/·
' .с,, · - ~.'" l' .,--с. .• ..J ,,",,=.ry t
j- '\;, .... = 1''''"''''~'c:o ~.,s. " .,• '. . . . .
_.I..!:! -~""
.. ~ •• ~,~" ,J == 1.!"t""~""';~":
/1
-/ I qцщp'Sb~СО1О11::"
ft
r
876 Часть IV, Программирование с помощью бибl1иоте к ,NET
Посл ед ними элем ентами графичеСI<ОГО интерф е йса в этой форм е будут типы
Labe l и But t on . которые таюке будут с конфигурированы и вставлены в коллекцию
Con t ro l s формы с помощью I nitia liz eCompon e nt () . Тип Label и спользуется для
отображения информации заказа. формирующейся в обработч ин е события Clic k
кнопки B1J t to[) подтве рждения заказа . кан показ ано ниже.
Обратите внимание н а то . что как Chec k Box. так и Rad ioHLlt ton поддержива
ют свойство Chec k ed . которое позвол.яет выяснить текуще е сос тояние эле мента .
Кроме того. напомним, что если вы сконфигурировали C11e ckBox с тремя состояни
ями, то состояние элемента нужно проверять с помощью свойства Check State,
L
Элемент 'CheekedListBox
Тел~рь, аа:вер:tl:I.ИJ:! И-СQлеДQванйе- QаЗОВЪL't'8Jl'еj\{енJ'ОВ уnрав.пения. Е Ь t t .Qh. да ..
вайr:r,е рассМ,g:грим набор -ТиПов CI1tle-ка. 1J'-ЩСТRОCl~ Che с kedLls't.BDilL. Li 5 t E'I.oZ и
C0f11 bФE9~- ЭЛемeнr ::уnрШilле1iИЯ Chg,;ke d'Li stEo.x fr.щaо uтмеча_~l'.ЮГD mrn:сiШ)', позво-
ляет еrругmиро:8аТЬ '(IО!9тветет.вующие эдем~нnn CbeekВo.x в enи;r;-...JШ/ Д;QП)'СI~а..'ОЩИЙ
UРСЖ:РУJК,У, Пре,цш.mmю;rм. 'ЧТо ВЫ .добэ.вшm 13 форму элем~ YIWIOmешш Са!! CGt'llig.
да[GIЦий. мл:ьзова.тerao вс>эмоw..нос,тъ У'кавать на выБQР ' fЩд хаР:ut.r.ep.иcrИR. "НоторЬ1'М'
~llШа УДОВЛВПlор.ятъ. система ЗВyJ\ОВt1спрощt:ведеИЩ1 автoм.oбшtЯ (рйr.. 21 ;9).
Ф.!ЩIIМ P<Iд~II""'"
o T'bII!<l!!SR АС
I~.. ~ .I
. ~ ~r
q;,;~~~~~;:·Ii:;~,.;,.,w~ a~,
I ~ Jl f.lW~ T~ni:lUJ.~I~
СО1l14"'PII!ИQ. У./1!>.,.р~-!j.с. (сo!i'.!(фер)
Ч'):'обы дuбацЩ"Ъ в Сl'нэ с'kе d Li Bt:Вox НOl!ble gлеМенты. вызаБ~ A o'd () .ДЩJ Иf1н<.f(О
то :элемента NЩ1 0'еIЮ~JiЬ3Уйте метод Md'R,oi!IJg'.e!) с :м:аСOiRОМ об,,~RТО.~ (';:ЧJОК, еwш
б1;41'1> TO~ЫМ). I1редстfМn..я:ющиx веаъ lm:бор отмечаеМЫХ :ЭД6~Т~J:I удр,ав.пeюm..
('.1J€lдyeT знать о 'ТОМ, '"ЧТU· ·Б т).ежиме проекl'ИРОМЮШ дюбой тип CI'Ц}CI@ :мо.щ:н-о· яа
DOЛЮlТ'ь (' rЩМ(IЩblO с~оЙt''JltW Jt-e.ms й!Жне свойств· tnpoc"!'co ЩeJIКF.rщ·е 1'!~ ю;ri:л:J:Ee G
ЮIOl'оточие:м H~lJ@дnтe под1tO~ ~ТРО1Ювъrе значения) . Вот ЧErСТЪ lJрQrраммлОГti>
"од.а J r\ i't i/ij 1 'L z~t&~~"'(1 Гl8Тr'Ц) • coO'I1!e.tc-rnующм Щl}Н;!Ц'lrypадlШ CJ!e.c:~.jLj $ tR-о,х..
1/ cl1.eeked1!6XRadiOQption,s
11
j: :.й в . t'l1З i: k·e:dB0 xR·.:;'j·r,1 i o.Opti Q j~S .lt. e....rrт s . дt1dRшtg t= ( IЗ !1'\'/ з.Ьjвс t []
" ФрО аТctJfI:.?ia-@ AC ".r 'JЭ~:к:а..;i а.Тlb Н.ыИ ЗЗУ.К'! ,
'''CL'~ !J?О !1I'?ЫЗ.<:J те-л ь о. , 'О 'кас'efO' lPц:ъ& UF-:оиг,рЫВ <I''l'.Е:J:{;;' '' ,.
"'I:ь.щij'ь-ая А{; ". "1:" JJ ь. Т-Р 9:~б.а се "{.сабl1!уФ еР .I' О J 1 ;
J
878 Часть IV. Программирование с помощью библиоте~ .NEТ
Теперь обновите логику обработки события Cli ck для кнопки Подтвердить за
каз. Выясните. КaRие из элементов CheckedListBox в настоящий момент отмече
ны, и добавьте их в строку orderlnfo. Бот как должен выrnядеть соответствующий
программН:ЫЙ код.
orderlofo += "-------------------------------\п";
11 Для каждо:rо элемента мз CheckedListвox.
f o r ( i nt i = О; i < checkedBo xRadioOptions. Items . Co unt; i ++ )
{
11 Отмечен ли элемент?
i f (checkedBoxRadi oOptio l1s. Ge tltemChecked(i))
{
11 Получение текста элемента и добавление к orderin~o.
o rderlnf o += " О ПЦИЯ радио: ";
orderInfo += checkedВoxRadi oO ptions.ltems[i] .ToString() ;
o rder ln fo += "\п";
ОпЦII.Р"~_
iO ;Рpoнr~1Ь_АС
-- -- - -'- -' -l
Элемент Li'stbox
ка1< уже ynОМИННJJОСЬ выше, тип checkedListBox: наеледует больШИНСТВО сво
их ВQ3МОЖНQj::те;й. от пша Ызtво.х (окно CIIИCIЩ). ЧТQбы продемоцстрироватъ ВО3-
~ожпост.и ИСЦОJJIsэования типа Li зхВ"о-х. д.аваЙте добавим а НЩD~ uриложен:ие
t:a гСоп fi aJ ~ОЩ:МОЖflОСТЬ выбора пользователем марки автомобиля (ВМW, Yugd и
т.д.j , на РИС. 21.11 поу..аэ8Н :внешний ВИД ТОТО пользо:вательCRогоинте:рфеПса. ко
торый ~MЫ ХФТИМ ПОЛ)'ЧИТЬ ,
м....- s.aoto
, .·~oe~·; Ц~T.
'QrЦ.t~"""""" W''Пi'OИfJJЫ·аТ~Rb
11 carМa!keblst
!I
t h i s- . Сд.IМ-аkеLiБt .НеIТLЗ. АddRа пgе
(I'!ew o'bj ect [] ,1
"PlМW", "Ci.1:t:a'!l8.JIl", "Ford", "GJ:;and Am" I
",J€€1?" I ".Uet ·t i;J", "З'ааЬ" ., "Vlper l1 r "'YU{[C" 1);
Элемент ComboBox
Подобно ListBox. тип СоmЬоВох (комбинированное окно) позволяет пользова
телю сделать выбор из вполне определенного набора возможностей. Однако тип
СотЬоВох уникален в том. что пользователю ТаЕже позволяется вставить допол
нительные элементы. Напомним. что СотЬо80Х получается иЗ ListBox (а послед
ний. в СБОЮ очередь. получается из Co1'1trol). для иллюстраЦии возможностей ис
пользования рассматриваемого элемента добавьте в форму приложения Са r(; ollfig
еще один злемент управления. который позволит ввести имя продавца. с которым
пользователь предпочитает иметь дело. Если имени нужного продавца в списке
нет. пользователь может ввести соответствующее имя. Одна из возможных моди
финаций интерфейса показана на рис. 21. 12 (можете назначить продавцам такие
имена, какие захотите) .
.. .
~ Пfжуrща HOBUH "МIUИНЫ ~J©J~
ПрQll,.....ц:
з~п~сные КOI!Iрики ДI1Я.МОWИНЫ
Ц_ет
Подробноcr" "11"""":
/1 comboSalesPerson
1/
1
!
rJtaBa 21. ИGnО)tьзован~е эле М~kИВ уnра'8llеflИЯ WщiQw,g Forms 881'
tl'1i з. . c~lmb.'OSa lе БР€o1: 6'0[1. 1 t-еro'з, Ad,jRange (iT8 Vl ODj е ",t l J
" MilI~:a Би-Би " , "дЭ'!'J \"М~Ш>1р-а\'" I
·el~ fZ
.С> I'~!f:' r 1 Il f·o += " Вы не указ.а= ИМЯ U}'JDЛФ Bil.."i! " ":' ,, \ r'l " ;
J
т
882 Часть IV. Программирование с помощью библиотек .NET
_-_
. ...... - ~. ~-
0--
п- --·
..._._ _ ___ _
-----
_ _. z-
-~
О"ет
l!iIелeныi< 1!I~1пыi< 1I!Jo3О11ый 111""011""
liJap",,:
lJiW ~ .--- - .~ - ~- ~,!
IС",,,,,ал :·:1
I Ford :
e,(il an9 Am ~ - - - _ ~
ШQ»DБНОСТ. зака .. :
3амечаНl4е. В форме МОЖНО так"ке имитировать Щel1ЧОК Щl n!OnKe· Сапсе! ('Отмена) при нажатии
1ТользоватеJlем I<!тавИши <Esc>. ДЛЯ iJj'fQrD НУЖRО НLlЗНеч\IIТЬ свойстау Са n с ~ 1 Вц t t Gn >1МА
06ъеlml But;.ton, прёДGтавляюсцего I<НCiПК\" Cancel (Отмена).
• Тоо1Т:iр
• т.аЬСолtrol
• Pa!le l
• Элементы уцрЮЩ~I:П1Я t.1pDoo;r,
• E:r:::rorFrovi:der
Элемент MonthCalendar
Пространство ИlIlен .вуз te..m. Wli,c(pws . F('r'П'.s nр'едлаг~е:r очень IlliлеаНЫl1 эдемент
упраЩlе~<я Мо Dt h С зJ :ела.з' r. tWторый дает ПОЛЬЗ0ваrrел~ возможность выбрать
дату (и.llЦ диanaЗOf'I дю). и.спользуя .цружествf'.ащ,IЙ интерфейс, Чтобы продемOfl
стрироватъ ЭТОТ элемент ynpэв.лtlliИЯ. 06ншJИМ прило~ Ca.rConl i:g так. "fГобы
DОЛh30Вl:i'ТеlIЬ мо!' ввести дату доctавки XYWleHHQjQ :ГРfЩ,стюртного cpe~CTBa. На
рцс. 21 . 14 ПOIщз~а обновленная (и слеtна модИфицированная.в QТНо.uН!нии раз
М~еНИЯ ~лементовJ форма.
Элемент yuр;;шлеRИЯ M,jhth.C~ieridar имеет весьма ширшше .возможности:, и с
его IЮМОЩЫО o~eHЬ Просто- I1pOI'p1iLqI\'lНQ выпom-JйТь "за..хват'· диапазона дат, ыыбран
,ttь1X ПОЛЪ3QВа~ , Поведением ПО уМолчaдnю д.:1"{Я ЭТОГО' типа · яв.ляmсеа.втомаПi·
чем\ИЙ выбор (и выделение) теtt'УЩей (сеJ'ОДНЩШIей) да:.гы.
884 Часть IV. Программирование с помощью библиотек .NET
т
Onц•• paA.~~ Mapl<a:;
[ем\Г- ,
-' ---- -- -- '-- -- FQ'd
[дЖОН KOflecU
- .. .."- - .
_-- --- ~
[
,~T~!,d .~m _ _ , '
&U'L.'1CJ dвг.еЕndБtr =
s t r L'"ig . Fохrг/з;t 1" I С, I , I J r , ./ 2 I " ,
eJ'',{:iJi.DilY, f:'lidD,МQлtr1, endD, Уевг);
ti
a:r{t~.r::1 ГJ Ео += НМВILV11...ч.а _ГГ()ПЖ}.-f..п бьттъ na.~~ 'I'a БJг:е'Н:а \J!I
-+ lIё П+ d.аt.ез'!::.а::сt.;Э'tг J. 1'1 Т1(! тl ...,k l1ЕJ.tеЕnd.Бtr;
Замечание. WindOW9Forms СОД8р'Ж.1Т 3I1ем.щп управленvw t\,э t€Tiroe F.i(:' k е r, который ПQЗВОllЯЫ
предложить Ио:пtЬ:Саlелdа r i! рвскрывающеМС!1 элементе уГ\равдеНИ>I Drоr;D'3'AlП,
Элемент ToolTip
в е$3И с рассматриваt:>МОЙ формом Са rcon:ti q мы доmЮIb'I I1РОДе.~он('триро'
BaJ:b еще одну. з<tItлючительную. в.озможн:оС'ТЬ. Многие современные инте.рфеЙСh1
I10ЛЬ:ЭQватедя llР~ДД:агают ~ наэываемые еСТlЛЬi6QJQщuе rfQikК:бl.ЗКt~. В ар()стран
cт.в~ имеЕ эуst~m.Vifindоw'S.го:r:n\s эта ВОЗМОЖНQСТЬ тrpе1.J,СТЮJЛt;Щl ТИПОМ 'l'OolT'ip,
C()o:rBeT.t>TJ!Yl0Jд~e подСRа:з'&И :tIредс:гав,nя1ОТ собой неб(!).!]ъшие цдаваFФIIЩе ruша, в
lЮТОрЫХ отображэ.ютсл вс:цомotщ:елЫlьrе сообщенй'Я. Kor.Qa: нурсор 3<lдеРЖIШ~1:t'тея
:вблизи Д(lННЩ:;О э:.rrем:еl{'Г({ интерфейса.
Для примера добавь'те TaRyIO ЦОДСl\а:"шу ДJЦI каJreЩЩРЯ Ca'-':':оIJi'ig. Снач;) ; 1
// calendarTip
//
this.calendarTip.IsBalloon = true;
this.calendarTip.ShowAlways = true;
this.calendarTip.ToolTiplcon =
Sуstеm.Wiпdоws.Fоrms.ТооlТiрIсоп.Iпfо;
Теперь наш проект CarConfig можно считать завершенным. На рис. 21.16 соз
данная подскаЗRa показана в действии.
Элемент TabControl
Чтобы ПРОИJUПQстрировать остальные "экзотические" Элементы управления. да
вайте построим новую форму, пщщерживающую ТаЬСопtrоl (элемент управления
вкладками). Вы, возможно, знаете, что TabControl позволяет селективно скрывать
или показывать страницы связанного содержимого с помощью щелчка на соответ
"'!Ц>.".:
(ВМi/J- - ~. I
i ~;'lO!> ~. 1
_.- -
'!i'т~"d,Arn
, г -~- -~~
1 :1 ~ 4
~ З UI 11
j2 j3 14 1·5. 16 1:7 18
19 ао 2'1 22~,:цЩ
2Ii :n :1fj 2'J зо
При создании Злемента ynpавлен"'Ия Т;;;:ЬСоn tro 1. c.дr'дyeT учйтыuать 'JЮ, ЧТО R8.Ж
дал страница nредставдлетс.!I объектом т а Ь Р а 9 е. содеРЖf.\ЩИ};lСfl во ВНУтре~-!Не-й
К1)JD'1eJЩИИ стрaroщ Tabcont.rol. Оконфигуриро:щшпbIЙ Qбъе.-т TabCofJt.rol (по
добно любому ~py:['oмy элемеЕ'I}' rptIфичеCI<оrо интерфейса в форме) добавляется
n :ЮМJI.e:в:цию Сщн:rоls форм.w. Рассмотрите соответС'l'ВУЮЩц'й фра.r.:м.ен:'r ~eтaдa
1 гj i ti.a l iz(;'С'оmроnелt (:).
J
888 Часть IV, Программирование с помощью б"блиотек ,NET
private vo id InitializeComponent()
!
11 taЬControlExoticControls
11
thi s. tаЬСопtrоlЕхоtiсСопtr:-аls. Controls .Add (tlli s . pageTrackBar,s) ;
tl,is. tabControlExoticControls. Controls. Add (this. pagePanels) ;
this.lаЬСопtr:-аlЕхаtiсСопtrаls.Сапtrаls.Аdd(this.раgеUрDоwn);
this. tabControlExaticCon t rols.Cantrols.Add (this.pageEr rarPravider);
this. tаЬСопtrаlЕхоtiсСопtr:- а lS.Сопtrоls.Аdd (tnis.pageTr eeView);
tI",} з . tаЬСопtrоlЕх а tiс С опtr:- о ls. Cont.r:-ols. Add (this. pageWebBrowser) ;
tП is.tаЬСопtrоlЕхоtlс С опtr оl s.Lаса t iоп
= new System.DraWing.Point(1 3, 1 3);
t h i s .tabControlExoticC a ntrols.Name = "tаЬСопtrоlЕхоtiсСо п trо l s";
this.tаЬСопtrоlЕх о tiсС а пtr:-о l s.Sеlесtеdl п dех = О;
th i s.tаЬСопtr:-оlЕхоt i сСапt r о 1 s.Sizе
= new System.DraWing.Size(463, 274),
this.tаьсопtrоlЕхоtiссопtrоls.таыIdехx = О;
this.Сопtrоls.Аdd(this.tаЬСопtr:-оlЕхоtiССопtr:-оlS) ,
Элемент TrackBar
Элемент управления TrackBar дает пользователям возможность выбора иэ ди
апазона значений, используя нечто. похожее на полосу пров:рутки. При работе с
этим типом нужно установить минимальное и максимальное значения диапазона.
Свойства Оп~сание
I ,.___.
"~Тr$kE-..· ~ ?anOI i! Ijp6;;~:It_._
/ Е;r~iOI!iawJiТ~i;;'
-АWеЬ&;~,1
~ . ... ~~_ :l _ _
,
. -- :
КрасttЫЙ:
1_ , II I I
--_.)-. I
:: . ~~ .•. __ ._ •• ~_...._..
,
' 1'
Зеленый': t
J
890 Часть IV. Программирование с ПОМОЩЬЮ библиотек .NET
11
11 blueTrackВar
11
this.blueTrackBar.Maximum = 255;
this.bluеТrасkБаr.Nаще = пы1 JетrасkБаrп
;
;
this.b:ueTrackBar.Tic~Frequency = 5;
this. tiue'I'.r:ackВar. TickStyle
= System.Windows.Forms.TickStyle.TopLeft;
this.blueT.r:ackBar.Scrol1
+= пе" Зуэ tern. ЕvепtНапdlег (th,i s . bllJeTrackBa r _Scroll) ;
данные для вычисления нового Color с помощью Color. FromArgb (). Имея но
вый готовый цвет, следует соответствующим образом обновить член-переменную
Е'iсtиrеВох (с именем colorP.ox). чтобы установить текущий цвет фона. Наконец,
UpdateCo101 () комбинирует значения ползунков в строке. размещаемой в элемен
теLa.bel (lblCurrColor), как показано ниже.
private void UpdateColor()
{
11 Получение HOBO:rO цвета на основе значений ползунхов.
Color с ~ Соlоr.FrоrпАrgЬ(~~еdТrасkВаr.Vаluе,
gree:1Trac kBar. Va1UA, Ы aeTrackBar, \/а1 ue) ;
11 Изменение цвета в PictureBox.
colorBox.BackCQ1o.r: = с;
11 УС'1'аноnка '1'еКС'1'а дnя надписи.
1blCurrColor.Text =
string. Fоrгпаt ("Текущие цветовые ЗНачения: ({ О) / (1), {2))",
redTrackBar.ValuE;', greenTr:ackI3ar.Value, blueTrackBar.Value);
Глава ~1. ИСПО)lЬЗО8а~l(Iе элемеfIТО,В управлеНИRWinQОW$ FОПI1S 891
Эан..юочительн:ым штрихом является у.ставовка началъных.эначениii: каждого
пол.эунка при нача..ThRОМ ПОJ1ВЛfНI1I1 фQРМЫ и отображеюre текущего цвета, как
по:казано ниже.
риЬН с МаiпW,iш:iоw()
Элемент Panel
как 'вы уже :видели, элемент управления G:rC)lJpBCix может использоваться д.ла
ТОГО:, "Л'о6ы логически объединить ряд элементо:в управления (наnpим:ер~ neреlUUO
Ч'fi:Гf'лей) и заставктъ их фунь."'I:(ИОНttpова'1Ъ ВО взаимОС8ЯЗИ. Элемент управлеНИR
Р.шe.l в атом CМblC)Ш шщ.яе'Тся бш4.ЗКИМ к Gtou.pBox. 3лементы управления Panel
'I'оже ИСПОJIbЗУЮТ/;,:Н Д1fЯ группировки родствеlшых элементов управдез:ия в лаги·
ческие еди:mm,ы. ОДНИМ из различий является то.. что -ТИП Рапе 1 получается из
кпаесЗ. sсr э l lаыl·Qопt'l"с ,l • . ПI1Э'ТОМУ Раl1еl может подлержив<tТь подосы прОRpyt·
ки.. чего ' не'!' у G'I:OupBGx.
ЭдеМt>.JПЫ yuравлеии,н Ра'Л Еl могут тз..юне испО1rьЗ0ватЬСfJ ДlIЯ Wконсервзn:йи'" со
держимого экрана. Например. если у вас t:CТb группа элементОв управления. ПО"
торы\:! занимают всю J-Шзtmtoю половину формы. -ВЫ можете Поместить эту rpyuny
в Б'а,l1е1 ло:ловиннЬtо раЭlWrepа и ycta1-iовитьзна:чеНИ(J т..ти:е (и:стинэ.) д:пя свойства
All t 0 '$ o.r: 01 1 . Тшда пользователь сможет использовать палосу (ИJШ ПОЛОС""1-) про
крутки, чтобы просмотретъ весь :набор эле~lеН''Г()Б. К TQlVIY же, есJШ ДJ1Я свойства:
Brxrder3t,yl e Э.чемеШа Pan-el устанDвитьзнэчеНnе NOri'€>. 1"0 э1'ОТ ТИП МОJЮJО будет
иcnользо'вать для гpynnировкн набора элементов, КОТОРЫ'е очень л~rКQ ПОJ<азаrrь
:или C1tPIiITb способом. COflepiueHHo п)Jозрачным в ртношеюm кон~чного ПOJIьзо
ватeJiЯ.
. [ё!?~~_п;;;_l
,
,
ci
!
Tt' llepb обработайте событие Cl ick для каждой кнопки . Как вы можете догадать
с п. нуж но прост!) скрыть или пов:азать Pa.ne l (вместе со всеми содержащимися та.Г\1
ЭJlе Мt'птаюlof пользовательского интерфейса).
~(,ЛН теперь вьшолнить программу и щеЛlЩ:УТЬ на той или друтой КНОПRе в со
отв етствующем окне, вы обнаружите. что содержимое Panel соответственно по
казывается и СRрывается. Конечно , этот пример не производит слишком большого
впечатления, но я уверен. QTO вы смогли увидеть ero возможности. Например. вы
можете иметь ПУНКТ меню или ORНO безопасности, способные предоставить поль
зоватеmo "простой" или "сложный" набор элементов. Вместо того чтобы вручную
устанавливать свойство Visible равным false (ложь) для множества элементов.
вы можете группировать их в пределах Рапе} и соответственно установить одно
свойство Visible.
Элементы UpDown
В ра~шах Windows FOпns предлагается два элемента. фУНIп~онирующие, как
элемеFtlПЫ уnравлеm!Я с 1lРQкруmкой (также известные. JШI( элемеfimы управле·
fiL!Я UрDошп). Подобно Сот ЬоВох и L ist Б о х, эти новые элементы также позволяют
rтолыювателю выбрать элемент из некоторого диапазона возможных элементов.
ГЛQва21, ИСПОЛЬЗОllа~еЭllеl.(ентов уnра:вле!/и~ Wir,dows F1)rms 893
РаЗНИ:Цii в том., чтО npи исполыюванци ~лемента ynpЮЦlеmlЯ DomainUpDowr)' и:.тra
N1lТneTic lJpDown варианты ВЬtбцраются: с UОМОIДЬ'Ю -небольши'!' ~трело~, направля
ющих вверх и ВНИЗ, ВзrЛf.ltt»Те, НaJIpИJ\-tер, на рис. 21 . 20.
. .
'j:1 "ЭК3IJтн',вСl< ..С" -",,,,.j;! Нl.' У"РдП,1е "")1 1;'lfSIFX I
.I T;:"ci(B~J!'.. ~~ 1" U~D;~" I~t';,Pm~: fr;;"y~...1W~I-J..... ~ ~-. _ . - --..
I
1
: ЭЛЕ:I"It?нт ,DQmа lпUрDо,wn ~~~~,~~;ir ~~ _ ~ '~~ ,
СаоЙс.тво Оnисанме
Свойство Описание
Свойство Описание
Вот та часть
InitidlizeCamponent () , которая задает конфигурацию NumericUpDown
и DomainUpDown на этой странице.
р]' l va te '10 id 101 tial izeCompooent ( )
11
11 nwnericUpDown
11
privatE' '''1)1.С! Ьt.J1lS ет.$'i'! lе.сtiолs_С liсi'J( (abjet:Jt SiЭиdет I Е'\тепtl\:r.gs ,е)
[
/ / По:nучение ииФориаЦ'ИИ O~ э.леиewl'QВ U})bown .•.
1i~1С' ь п$8 i . Text. =
stTing . Forma1. I .. Стро ка: f о ·} \ J'1. ЧИС;Г! О ~ 1] f ",
dOJ!\", jJ'i!JpDowrl. Te:xt, Гluw ~r± ~llp-Do.wn. Va} LJe) ,;
Элемент ErrorProvider
в БшIы:IIпствеe npи..11:0ЖениЙ Windows Forms приходится. тэн или иначе:, про
верн'гь правИЛЬНQСТЬ поЛЬзовательсRO.ТО ввода. Это особенно IiдCaeтCfl- диадФГQБhIX
окон, пQС'кольку.вы ДОЛЖНЫ ИНфОРМИРDвать пользователя Ь том. ЧТQ он еделал
ошибку. прежде. чем лользователь nPQДOJ1ЖИТ ввод. тип E:rr o.:rP !"p~1 ider -может И('
IW-льаоватнG.Я длв' 'Гота. -чтобы обеспечи'ГЬ пользователю 'Виз}'алЫIые подска3~ .Б ОТ
ношении, ошибок ввода. Т1редrtoло.жим. НaIJpимер. что у вае есть фQрма, содер;;ка,-
щап элсмeк:r:ы ТехtБ-QХ и Euttmi. Если ПОЛЬЗQватещь введет 8 ' Тею:Вох бодее пяти
симвoлDв и Тех:tВоя утрачивает фокус ввода. м.ожио отобразить l1НфОРмацию. по
ка:эmmую на рис. 2'1 .21.
-
"'!: "JI(ЮТl,'IРг.к",," з~е.I"'нты y"pa"~eH"-" r:-11'~If5(!
DК
12'1456
L- c _ _ _ _ .... . _
С3. 'U.sеsVаl id а t iол Индикатор того, что выбор этого Эl1емента управлени~ вызывает
проверку ввода ДЛ~ элементов упраВl1ения, требующих такой
про верки
Тип E:r::r: orP rov i de r: пр едлаг ает очень небольшой набор членов. Для нашето
ПРИl\.ol ера самым вaжньrм является свойство Bli nkStyl e. RОТОРОМУМОЖВО присво
ИIЪ любое значение из перечня ErrorB1 in kS t yl e , Описания этих значений даются
втабл . 21.II,
Значение Описание
Вlin.kI fDiffе геп[Е rrог Заставляет пиктограмму ошибки "мигать" , когда пиктограмма
ошибки уже отображается , но элементу управления назначается
строка новой ошибки
/1
// tooМanyCh4ractersErrorProvider
11
tbis. tJ:>оиаТl'Усрёj.Iaс1l.еri>Е·rrqrР:rо'....idе,r . Е l.LnkRa·t е ~ 500';
thiJ3 . tооJ.l1aлуСhю.-а c:t..erS'EITQr?rbv lder. 131 i,г.kstуl е =
S yst.ern. w{ndc,w;;,;. FоnnS ..БrуоrВl inkS't1йе .}uwa y.sВl in,k..;
thi$ . t ·QoMa.l'lyCbar <'!ct'e ['sE:r:! OJ;·P:!ov..ider. С'эпt аi!1.еrСолt tQl = this;
Элемент TreeView
Элементы управления TreeVlew очень полезны тем, 'tf'fO они позволяют ·визу
альна ОТ0бражатъ пера.рюlИ даН1{ЫХ (наприМ'ер, структуру КCJ,талогов или :ЛЮбуЮ
другую структуру, связанную отнощеRИ~ ~РОДИ'J'tЩb-:nОТОм(m"J. Элемент управле
ния T:!:?eeView предлarает очень щирmше ВQЗМОЖНОСПl НCJ.C'I'ройки. При желaнIOi: вы
можете добавить Dолъзова:тельС1iие И;ЗОбl'ажен:и.JI. за.дат;ь Ц:В~T УЗЛОВ, элементы КОН
'tpОЛЯ .Узла и дРyrие ВИЗУW1Ьные усо:верщенствования:. (8ЩIНТересQВанным 4ИТате·
лям за )J.Оl!оnнитеJПiНОЙ инфор~аЩ(еJ.i об этом Э.1'Jементе управле~я предлагаетел
обратиться к докумen-rации .NEТ Fram'ew:ork 2.0 SDK.)
Чтобы nродемо.нстрироватJ;. pcцoBlfЫe возможности >:I~.ПОЛЪЗО:Вa.ншr Tr.e eView.
на следУЮщей ctpaI-lИl'(е вашего Ta;bCor1t.rol мы npoг~o раЗМесТИМ э.11емент
Тз: eeView. оnpеде.IIЯ.ЮЩИЙ ряд узлов 8аив,ысшеГQ уРОВИЯ' , рредdтавJ1ЯЮЩИХ набор
ТИПО!! Сат (а1tI'омобилЬ). Каждый узел Ca.,r имеет ДJЩ прдчmtенныхуапа. предетав
.nяющux те!tyщую (]1(OPOCT~ аВ:ГОJ'4(j)БИ.ая и люб»мущраДИОtJ'rанцию водителя. На
РИС, 21.22 обратите внимание па то. что выбрalф.ый: элемент выделен псщсйет:коЙ.
Также 38Метже, что в области элемента lapel нроме выбранного узла отобража
Ются имена родительекого и сnеДУЮЩ~ГQ узло:В (есЩ1 по('..nедние име1C1I'CЯ).
898 Часть IV. Программирование с ПОМОЩЬЮ библиотек ,NET
т
l!!-асkвilf~IUPD~-Е~~ Т,Oevое~~~_. _ _ ____ __ ,
i : ~ с.,:О" ~i Вы Вbiбpas&<: Ci<oPOCТb: 1, i
'1 i [корость: 1 О ;~.;"~;.: I · Родите1JbСКИЙ y3eJt C~ 1
СneD.!lЮЩ~ узеn: Любi<мое рмио: ЗО.5' FM
i; Люб"мое Р.oD.ио- 90 FМ S;~ 'I
I i SI и.гl I
!! _5М'М., j,
11 .н с., ~юбимов рааИОI 90.5' FM t
Ii - CI<OPOCТb: 12 11
!I I 6i
I
Любимае раа",,: 91 FМ
См 3
.{'
ii Скаррсгы 13
I, I i±J.' car4Любимое p.wю, 91.5 FМ !
t
class Radio
Bui1 dC.arT.r'eeVi~to; () ;
}
}
900 Часть IV, Программирование с помощью библиотек ,NET
т
Кап: видите, каждому узлу TreeView можно назначить изображение, цвет.
шрифт, подсказки и контекстное меню. Кроме того, TreeNode предлагает чдены,
позволяющие перейти к следующему (или предыдущему) TreeNode. С учетом этого
рассмотрите начальную реализацию BulldCarTreeView () .
private void BuildCarTreeView()
[
11 TreeView не оmображаеlJ!СИ, пока не созданы все узлы.
treeViewCars.BeginUpdate() ;
/1 Отображение TreeView.
treeviewCars.EndUpdate() ;
,i
'!
•... ___ ~ ... _____,_ __ .J
ок CaO=I
Вы ДОЛЖНЫ помнить из главы 20. что при добавлении в проект Visual Studio
2005 ресурсов [таких. как точечные рисунки) автоматически обновляется соответ
ствующий файл *. resx. Таким образом. изображеЮiЯ будут встроены в компоно
вочный блок без каких бы то ни бьшо ДОПОЛЮiтельный усилий с вашей стороны.
Теперь. используя окно свойств, установите для свойства ImageList элемента
управления TreeView значение ImageListTreeView (рис. 21.24).
. n.
~ _Ч( IОТН .... (ч.IО1f·
., I 'PtU"Hlbl '/пр ..НllL'НIo1Л
1. - '1 '-'
'~
'х
I_ I
3neMeHTWebBrowsers
На IIО'СлеДНе.(I странице .в 9TO~ пр:имер:е будет щ:;по~зоватьея элемент управ
леШIЯ Sу з tеm.W.ir:ld о ws.F'о r.ms.WеЬВrоwsеr, lfотарщ появился толЬЕЮ.li ...NEТ2.6.
Этот эдемент управленил пред€тащшет собо:if ошюмщш-обоэревател.н Web. встра
иваемЬrо 11· дюбой тип FQrm и оfuтздmощеrо очень ШИРОI<ИМif. воз.-можностями на
С троШш. I{aR и сдедУет Q$ИДc;l.ть, этот ЭЛ'е.м{ЩТ уцравл~:ЕЦiЯ определя-ет свойство
Пг 1. КОторому может быть црисвоено любое дейс;гвительное значение UЮ [U.nifoз:m.
Resouree Identifier- yнnфицировапН:~IЙ НiI{ентифщштор ресурса), Формam.'Но пред·
СТа.БЩIемое ТИПОм SY$tei!1~. Ori. На ЩшaдIo/ WebBrow,s,er до(18Вьте Элементыупр8.В-"
Л~НЩJ ·WIдЬЕrо.wsеr (е настро:(щаьш по вашему выбору), TextBo.x .{для ввода адРеса
URL) и Butt9il (для въmОЩlения: НТТР-зanpосо:вl.· J-Щ рис. 21.2~ показал вид eOD'J'-
ветствующеro окна в режиме въmоЛ»e.дИfI 11 момент назначеюm свойст.ву Пr 1 эна
чения http://'www,intertec.h.tJ:q.ining·, c0m (~. это имеЯRО ·ТО, о чем.БЫ еей'часло-
думали - б.еспаРДОН:На$ реклама 1\0МIIa..IlИИ. в .которой я работаю).
т
!
~\Т:.nE~H TМI~'MB
Th8 ,"oT/e.• 1 4.н/I."" be/llIto\
lеiи"ing .. "d d.i"g~
.P!\I~ tl'l*t
IJI' Vls~ С"
. ~
ii' Smer:~ Devlco
, !JetlbllS8
~~IrW
1ii' 00er~
!*' other PrOled Types
[ ott Il c.t)C81
Перед тем как двигаться дальше, давайте рассмотрим общую картину того. что
мы ХОТИМ получить. тип CarControl отвечает за анимацию серии точечных рисун
ков. которые будут изменяться в зависимости от внутреннего состояния автомо
биля. Если текущая скорость автомобиля значительно ниже предельной скорости.
для CarControl ци}(ЛИчески будут отображаться три точечных рисунка, представ
ляющие безопасное движение автомобиля. Если текущая скорость всего на 10 км/ч
ниже максимальной, для CarControl используется цикл из четы1ех риcyrшов, где
четвертый рисунок изображает автомобиль. медленно распадающийся на части.
Наконец. если автомобиль превысит максимальную скорость, циклы CarControl
будет состоять из пяти рисунков. где пятый рисунок изображает "обреченный" ав
томобиль.
Создание изображений
в соответствии с представленным выше проектом первым делом нужно создать
пять файлов *. Ьтр для использования в циклах анимации. Если вы хотите соз
дать свои пользовательские изображения. выберите пункт меню ProJect<=:>Add New
Item и укажите пять новых файлов точечных изображений. Если вы не хотите де
монстрировать сваи художественные способности. можете использовать изображе
ния, предлагаемые с ИСХодным кодом этого примера (но имейте в виду. что я не
считаю себя большим специалистом в области художественной графикиl). Первые
три изображения (Lemonl.bmp. Lemon2.bmp и LеmопЗ.Ьmр) демонстрируют вполне
безопасное и аккуратное движение автомобиля по дороге. Другие два изображения
(AboutToBlow.bmp и EngineВlown.bmp) представляют автомобиль. приближающий
ся к максимальному верхнему пределу скорости. и его "безвременную кончину".
Реализация CarControl
После этой ПОД1'отовите.дьноЙ работы по соадЩIИЮ цодьзовательекого интерфей
li;3. ВЫ :мощете rrристуцить к реализации членов т;ииа. Сначала создайте новый об ..
щедос'l}'IIНЬ1Й:переl:.~ень Anim'P'rames, 1(ОТОРbIЙ будет Щl.{етq "'Щены, лредстamшющие
RaЩ:IU>!Й :шемеgт ИЗ Imag€Li st, Этот переченьбудет И(~ДОЛЪ30ваться длн 011ределе·
НWJ 4еJ\yЩего фре11ма, предВ'аанач~lНОГО ДJ1Я. ВИЗУQЛИзаци:и в PictureBo,X.
Замечание. HanDM.fH1M, что ·"настоя.u.u,;i1 14 палноцеННblЙ" д~легат СОМ. таву В) должен указать ДВВ
аргумента. первым из Koтqpbl~ дрлж-енбыть .system .ОЬ] е ~t (прецставЛЯЮЩI4Й QтnрввитеJ1Я) .
а ВТ{)РЫМ- тип. ПРm'l3S0АНЫЙ от Sуstеm.Еvепtлrgs. Однако дляна.шего примера ВПQЛl1е
ПОДОiilдв-т и ПР~Qженный выше делегат,
lsMim = vallle.;
;!:ma,qe'Timer . Enab..led ;:, I.sАпiJfll
}
Свойство Pe.tName выполняет то, что и следует ожидать. :исходя из его имени.
инетребует DОДрОбm:.Dt комментариев. Однаш> заметъ'Те. что при УGТЮЮВКf:' ПОЛЬ
зователем соетветствующего имени вЫIIО.iIFIЯется. ВЫЗОйТnvаНdаtе О. чтобы это
~ саrС:Ьлtrоl Dтобразилосъ в нижней прлмоуго:льиой облаСТJ! эле:м:ента управ·
ления (сам это]: шаг будет сделан чуть позже).
/ / 8atбор Jl.Ql8JIК ~.
public st.ing Pe~Wame
!
get{ret·u:!'n carPetName; I
91 О Часть IV. Программирование с помощью библиотек .NET
set
carPetName = value;
Inval ida te () ;
currSp = va l ue;
currMaxFrame = АпimFrаmеS.LеmопЗ;
)
// Вблизи взрывоопасgой си~уации?
if ({maxSp - curr Sp) <= 10)
I
/ / Превwшaем?
if (cur rSp >= maxSp)
{
currSp = maxSp;
if (BlewUp != nul1)
(
B lewUp {"M-да
.. . тебе КРЬПliКа ... ");
c urrMaxFrame = AnimFrames.EngineBlown;
как видите, если текущая скорость становится JШШЬ на 1О км/ч ниже макси
мальной допустимой скорости. вы генерируете событие AboutToBlow и сдвигаете
верхний предел фреймов анимации R значению An.imFrame s.Abo utToBl ow . Если
пользователь превышает возможности вашего автомобиля, вы генерируете собы
тие BlewUp и сдвигаете верхнюю границу фреймов к AnimFrames.EngineBlown.
Если скорость ниже максимальной . верхний предел фреймов остается равным
AnimFrames .Lemon3.
L
Глава 21. ИСflользоваН)4еЭJlеМ~tjтое упрзвТ)еН·1411 Wi·лdоw,~ Form~ 911
Контроль анr.tМации
Следующей задачей нвля.етсЯ Обееиеч.еви.е гарантий того, чтО T1m 1':1 mer сме
стит текущий фрейм визуализации в раJl.Шах Pi.ctureB.ox. Снова напОМНИМ. что
"кисло фреймов в цикле апим.ацми ·завиСит от текущей скорости авrомоби.ля..
НеоБХGДИМОСТЬ изменеНИfl1>l:зображений в pictu'teBox l'Iозmшает rОJIЫЩ 'Тогда. ~oг
да СВQЙСтво AВimate равно true (истина). Начните с обрабоТitи u.oб'ЫТИЯ Tick для
ТЩJ.a Tiruer. шшользуя следУющий программный :код.
'Отображе"ие названия
Чтобы заверши1Ъ. СОЭДаЕШе элемента управления.. вы iЦОЛЖНhJ отобразить назва
н.и~ Щ!томоБИJLff. ;Цлл этого обработаИте событие Paint ДЛЯ Cal'C.o nt.rol и в рамках
обрабртчщщ эт()го события ·ОТОбразите РеtN.а.пlе вашего Ca-rСоnt rol Е нижней npп
моуголь1'IОЙ о&л:ас'Ти JWИента.
l':~~~r~iubra;y:~r~;;;ro\__ ~ ~-=-~ ~
Pre ~iew:
_, __-_ ~ ;R~ I L~
50
~:~: '-'о ' ": - . , .- : ' ' ' - _ :.;.~.'" ~I
i
Создание пользовательской
формы для CarControl
как и в случае любого другого .NЕТ-типа. вы можете использовать свой ЗJlемеит
управления в рамках любого языка, совместимого со средой CLR. Закройте теку
щее рабочее пространство и создайте новый С#-проект Windows Applicatlon с име
нем CarContro l TestForm. Чтобы сослаться на пользовательские элементы управ
ления из Vlsual Studio 2005. щелкните правой КНОПКОй мыlПИ в любом месте окна
Toolbox и выберите пункт меню Choose Item (Выбрать элемент) . Используя кнопку
Browse (Про смотр} на вкладке .NET Framework Components (Компоненты .NEТ), пере
йдите к своей библиотеке CarControlLibrary.dll, После щелчка на кнопке ОК вы
обнаружите в панели инструментов новую пиктограмму с названием. конечнО же,
CarControl .
После этого поместите новый элемент CarContr ol в окно проектирования фор
мы. Обратите внимание на то. что при этом свойства Animat:e. PetName и Speed
тоже появляются в окне свойств. Точно так же, как и в случае испытательного КОН-
,
Глава 21.ИСПОn'l>аован~~ злементов УI11)ilНJ1ени'Я WindaWs Forms 913
тейнера:, ват элемент ynpамения ~ЖЩlет свое:й жизныо" !J режиме проектирова-
1:I.ИЯ. ПОЭ'{iому. ест! вы установите.дщI свойства Ani mcate .зна"'1сние t лш, вы }~ДИ~
те анимаjIИЮ автомобиля в (щи е проектироваНИ11 формы.
Сконфиrypировав начальное соетояние CarContJГo ;L , ДQб81Jъте дополнительные
элементы графичеоного интерфейса. которые ПQЗВОJЩТ увеличивать и уменьшать
CROрооть автомЬБЮl1i.. а пucже видеть T'~ СЦОРОЩ'ь авто'Мобиля.:и страховые
данные. посылаемые генерируемыми СQбытиЯJIЩ (д,ля этого ВПCJlIНe II'Qдойдyr эле
менты управления l,a b e l ). О.nин из возмо>IЩЫX B<rPI:lWiTOВ шжазан на рис. 21.ЗО.
pri vate \! Qid I1tпnетi сUрDеwnс:аrSрееd_ Val ue.Ch~'IJ')ged (e'bj еС'!:. aen.der,
Evel1 t P.rg s е)
l
Гпав.а 2~ .. IAСПОЛl>зование элементов упрзвлеНИI\ Winduws Forms 915
[С'аtegоry("I(ОНфЮ'УРацаа 1I&1Ш!ИW") (
DеАCriрtiОn'("'ГеJ(8РИРуе~CR при приб.пииевии 1с npедещ С~ОРОС'l!И. "]]
pu:tlic ev€m t 'СаrЕ'VепtНашil.еr Ab.outToBlow·;
1
Гпава 21', ИСПОЛ,!'ЗОВЗ'liие элемеf!iТD8 упра'Вl1е1'lИЯ Windows Forms 917
Te..'W саМым вы гарантируе'I'е. тпо цри выборе пользоnателем '<Этого элемента
управления в реJюrnе rrpoеRТnраванця в QЮiе свойств автомаТИЧБСКИ будет ~дe-
лена свойство !'>ni'ma-r:.e. Точно тт{ ~e Д.1J8 зл~ента упраЩIенЩI указыцается ~'f;>r
fiиpаемое по умолчaI'tИю событие.
3..........148. Причиной встраивания ф8~nа ..... bmp аруч\,!ую (8 Отnичие ОТ CJlУ'18Я испальЗОВSНИR Т\1па
l'mageList) ftВJ1PJ!ТСЯ ТО, 4ТО Bbl не НазНачаете фвЙЛСаrСЬntrОl.Ьmр ЭI1EiмеttТУ ПОЛЬЗ0В,!Ic
те:льокого интерфейоа в режиме проектиро~ни:я,· ПОЭТОМУ Е;ООТВEl1СТВУЮЩИЙ файл, ". reSXHe
получает ооотвеlстаУID'ЩИХ обновлен~ых дattHblX,
1
918 Часть IV. Программирование с помощью библиотек .NET
Embodded Re,aurce
00 паt сару
Ac:tlbn
thCJ fta ",Iotes to the build and depIoyment processes.
Toolbo. ®
"А RicI)TextВax
Щ Text80x
~ го<щ:>
~~:::-~ TreeV\ew
I
1
920 Часть IV. Программирование с помощью библиотек .NET
I a~.~",
--'_
г--'_
· ..-'
,'j
____ "'i!,f'.;Й:( ~, ~~_~=-
§I
'- с
I
, . .'
. .
~J . < J 'Dki ' II ~'"'I".:;"~:
.,Iii' . :f." _ "- ;r - :< :'_"cт~ ,,<lf>t:" \'~ :>..
Свойство DialogResult
в качестве заключительного заданиЯ' при создании пользовательского интер
фейса выберите RНОПКУ ОК В окне проектирования формы и найдите свойство
DialogResult. Назначьте DialogResult.OK кнопке ОК и DialogResult.Cancel-
кнопке Отмена. Формально говоря, вы можете назначить свойству DialogResult
любое значение из перечНJ~ DialogResult.
Гnава 21. Иr;ПОЛЬЗl')вание злементр13 у.праВЛ'61-iItя W1ndows ~orms 921
рtфliС еDШn S,y stem . .\Hndows . Fопns . DiallDgRе:щlt
I
Abort., Can:cel, Ig11I.ore, No,
Nопе, ОК, Retty, Уез
а.Меч.Н...·• Чтобы оro~рааиrt. неМ!'ЩaJIЬНDS' диалDГОвое ОКI(Q ()ф10·рое. позволяет переходить <JT ро·
дитenЬClCой ф.ормы l( .!3)IзлоroвоИ' и обратно), следует "ызвать Show (') , а ке SbowDialog (.) .
Наследование форм
Qдt'ШМ из наиболее ЦРИВJJеli~ аспекТО8 nocтроения диалоговых окон J3
Windows Fbnns ющя.етои насдедовцние ФОР/-i. ВЮ. несомненно. знаете. ЧТО насле
ДОВание НВJJ.1IJе7СЯ ОДJ;iИМ из ба~08Щ ЦРIOЩЙПОВ оол, I<оторый ПОЗВDЛЯет OДНD1'dY
классу расшиpи'l'$ фующион~ность другого. оБы1но,' когда I'оворят О tiЗ.CJJеДО8а-
1
922 Часть IV. Программирование с помощью библиотек ,NET
dO$s
:?::
;~
II1terface CodeFr/t;' У'Лndows
fo,,"
Cuslom
Control
•• !лherrl<:d
\JSer Con!ro/
~
C",IDm
',!ieb
.Jj~
~
.,
Сomрооen! SQL Da!abase
~
'" , ;1
DataSet '(МL FIIe
~
XSlTAIe
lIJ
н'м.. poge
Cont'O/ C~ss
St,le 5heet Тех! F1le Bitтn.ap Frle CUI'Svr FiJe Imn File
Add J I CНrcel
public ItalicuserMessa~~Dialog()
!
InitiаlizеСоmролеntl);
!
j:;>x:iV<1te . s'triл.g· DserMessa·ge = "Def aiil t _~Je.!i!,·sage";
pr!vaite ьооl textIsItaLic = fa~se;
1
924 Часть IV. Программирование с помощью библиотек .NEТ
Динамическое позиционирование
элементов управления Windows Forms
Чтобы завершить эту главу, давайте рассмотрим несколько подходов. которые
можно использовать для управления размещением элементов управления в форме.
Если при соэдании типа Fоrrп вы предполагаете. что элементы управления должны
отображаться с испольэованием абсолютных позиций. то это. ПО сути. 0значает.
что кнопка, раэмещенная в окне проектирования формы на 1О пикселей ниже и
на 10 пикселей правее верхнего левого угла формы, будет там оставаться в течение
всей ее "жизни".
При создании формы, содержащей элементы управления пользовательского ин
терфейса. вы должны решить. должна ли форма ПОЭВОЛЯТЬ изменение размеров ее
окна. Обычно главное окно допускает изменение размеров. тогда как диалоговые
окна - He1.~ Напомним. что допустимость изменения размеров формы задается
свойством FоrrпВоrdеrStуlе. которое может принимать mобое из значений переч
ня FоrrпВоrdеrStуlе.
Свойство Anchor
в Windows Foпns свойство Anchor используется для определения относитель
ной фиксированной позиции. в которой всегда должен пребьmать данньrй элемент
управления. Каждый проиэводный от Control тип имеет свойство Anchor, кото
рое может принимать любое иэ эначений перечня AnchorStyles, описанных в
таБЛ.21.13,
Значение Описание
Bottom Нижний край элемента управления прикрепляется к нижнему краю контейнера
1eft Левый край элемента управления прикреn.nяется к левому краю контейнера
Свойство Dock
Другой особенностью llpOI'раммированил WinQOWS Fom1S ~теЯ ВD8МO)fmOCТb
задать ~ поведение элементов управления. С помощью ·своЙства Doek
элеменТа управления можно указать. ЩЩоЙ: CT(i)POHI:!l' (J.JlllII Jl:акИХ СТОРОН) формы
д1'iЛЖeJiJ касаТhСЯ данный элемент. Значение. 1Ю1'орое вы цаЗБаЧJПе свойству ООСУ>
элемента управления. учитываетcg вне зави<;m.rости от Т~}\.."УЩИХ размеров Q1ffia
фор:м:ы.. Допустимые зиачеltИя описaн:ы .n табл. 2] .14. .
Fill Все кр!!я элемента ~правления· стыкуются со есеми' краями КОl1тейнерного Э]1~
Me~lтa УПРЩlления. и соответствующим образом IIIзменяеТCfl размер
p-.. -,~-_. ' -:-" "" , ' c..>~"""_ ~~.~ :':-"-'::;::"~;::"7"" _ _ _ "'~_ ... -- -~"" '~-''''''''..:-'' •-•~
-::""" ....:.-1:-'1':..:.-
I 'fIowL")'Dutform.cs [Оеligп] ~~t.,Page [ .:" " о' ·· .Х !
I :
!
I
I
!
I
. - - ~ ~ . -
• 'ii, 'I<Ф1"t i!;lQl.ft~'<щltl . _ ci' х
М<!'!'<QIOI
;- - ~ -.-.- - -- - -~ -- =:3'
>110... 'Cdm:ls
r 1~ ;;,,~ ,_ _: _ _ _ ._ .- _ .~
_
,-- [ ..___
1'''''.
. ~~
y~
JO
е!ЩoalJ~
.,
Ca!ymt12 'Щ .!ЗtJ~. о Per=1 г-:-_~ , ,"
с.оUщ)
о AUlD5iZe
I i ' CGliпц~ ~"d!БW spanning,
I .~; if\!DJJwa"t.~..o<IIt<l11O <1'' ' f1Н1!tшl • ..,...,о1
~ иttloe'RO.61>.<''I .nd CoIumtt!;p.1!I
pfopblti~. 011 tIIe "'Л!ТJ>'.
I
...
~ ----_ .:....._ ~ .
ок JI 'C~
Резюме
Эта глава расширяет ваше понимание пространства имен Windows Forms путем
рассмотрения возможностей элементов графического интерфейса пользователя. от
самых простых (таких как Label) до "экзотических" (таких как TreeView). После
изучения множества типов. соответствующих элементам управления, была рас
смотрена задача построения пользовательских элементов управления, включая их
Замечание, В . NEТ2.0 сериализация типов DataSet (И" DataTable) может выполняться в ДВОИЧ
ном формате (с помощью RemotingFormat). Это может оказаться полезным при построении
распределенных систем на уровне удален~IOГО взаимодействия .NEТ (см. главу 18), поскольку
двоичные данные оказываются гораздо более компактными, чем данные XML
ного доступа.
PeatJиаОВDШlые
'мнтерФu'Ь!
ОБЬiМ1if ()f;;rI:jA-,'j:t'j1j!~IJ~Я'..
dбеtпеч'имe-r }Ю(lМO'ЖI4Q~ТЬ ею
$l'IlifеfJИR
I'i! ~вН'иriИ!цfJlA .цa:IJH\;J.j(
~,crrКil~~!t!Я, "N 1o!8Г~'t а ~1Qil~
дооryn ~ СХЩ:'1Ве'ТОТВУЮЩ!1МУ
оБЫ:llrrу TpaH3a~
O~1f1: ~lCtМаl'(ЦЫI,
П~JJ:стга"М1..sQL-заrrpOQ; ...i1J>1
I~MI'I храf.1:ИМ@И flp~ypl!iI'. 1:1
так.же ,Ь6еt;lilвq,IIIВШй'r.Ю!С.yт;Ii к
ооъещ 'Il'eH~il' ДЗI\IIi\:IIJI {';IЩП1.'l6Т
l,тsующtlго [1UС1Щ.jЩИI(В ШitIt\blJ(
запроса
I
-
Tra1ls·attic,n: -! I IЮМSfIДa 'Sel e~\
~lliзвr1.
()бъm fuIIrue:cti йа
-
1!OOл~?taam",t~s,
[ Ji.»;.ia. iIjI1dв tt'
I
- -
I 00ъe1<Т 'Da:tiiP.ei;!.d~ 1:
- - - -
I<DМO!\Qa Dei~te
I
Sybase http://www.mono-project.com/Sybase
Замечание, Поскольку число поставщиков данных ADO.NET велико, в примерах этой главы будвт
использоваться поставщик данных Мiсrоsоft SQL Server (system.Data. sqlClient). После
освоения материала, представленного на страницах этой главы, у вас не должно возникать
проблем при использовании ADO.NEТ для взаимодействия с другими СУБД.
Тип Описание
Интерфейс IDbConnection
ТИп IDbConnection реализуется объектом соединения поставщика данных.
Этот интерфейс определяет МНОЖество членов, используемых ДЛЯ настройки со
единения с конкретным хранилищем данных. а таКЖе позволяет получить объект
транзакции поставщика данных. Вот формальное определение IDbConnection.
Интерфейс IDbTransactJon
RaR m~:дите, п~реrру>:кенный ме'11Од BegiI1TrartSacU.onO. определенный интер
фt'.:й~О1\J IПЬСоппесtlоn. обесвечgвaет дощyn J{ абъеterrty транзакции поставщи:ка
данпъц. ИспоJIЬ3УЯ члены, oupC,I&JleНныe интерфейсам IDbТransaction. вы може
те осуществля.ть прогрarvrюше !33аимодf3ЙСтвие с сеансом транэакц;ии ~И COOTDeТ
ствующnм: хранилищем данньц!'.
Интерфейс IDbCommand
Интерфейс I .DbC o1t\mand. будет реЩШЗОВЩIобъекmо,м KoMal-to.ы. пос.тавщика
дaIlНhМt. Как и в других объeкntых моделщ доступа .к даI:IНЫ~.эдесь объекты ко
-мwщ позволяют npoгрВММIЮ обрабатывать БQL-операторы, ~J'анимЫе npЬiJ;едуры
и параметризованные запросы. 1<.роме ТО1'о, с пом;ощью rrерегруженнаго метода
Execut.eReader j} объе.х.ты команд обеcnеч:цвaIOТ ДDС'I}'Л. R объеК'J)' чтения данных
поставщика .дaнньut.
интерфеисыоьDаtараrаmеtеrr и lDataParameter
Of)paT~'I,"e ВЩIМaIOiе нз ТО,1!ТО свойс:rво Pa:rametexs ИН'Юрфейса IDbCo.mmand
ВQзвращае-r строго ТЩIИЗованную колленцию, реализуюIЦY10 Иllтерфейс ID:ataPara
mеtеrСоЦ.есtiоFt, Этот интерфейс обеспеЧИвает дocтyn кмножес'1'ВУ сQвм~стимых
с IDbDatliiParamete,r rщФВ кЛасса (например, DtrьeffГQB параметров).
1
938 Часть IV. Программирование с помощью библиотек .NET
ИнтерфейсыlDЬDаtаАdарtеr и IDataAdapter
Адш1ТТ!ерЫ данных используются для извлечения объеIСТОВ
Da taSet из хранили
ща данных и отправки их в хранилище. Интерфейс IDbDataAdapter определяеr
набор свойств. используемых для помержки SQL-операторов в операциях выбор
КИ, вставки, обновления и удаления данных.
Замечание. Перед чrением значения из объекта чтения данных можно использовать метод
IDataReader .IsDBNull () I чтобы программно убедиться в том. что соответствующее поле
данных не равно rшll (и не допустить генерирования соответствующего исключения в среде
выполнения).
myCn.Close() ;
l
Глав'в 22. Доступ J( (jазам nafjHblX t ПОМОЩЬЮ ADO, NEТ 941
1 DЬЕоппес t i фд COI1 n = n'и 11 ;
:;wit (;1'). ( ар )
!
с аЭе Dta t a PrQvi det. S.q1Se rver;
C Q!tJ1· =< new S ql'Co'nDec·t iод <) ;
bre.a k;
case ):Jat a Provid e .t.01eDb:
:::~JЛ'П .о; пеw .ОlеDbСО.'Ell1.е сt iол () ;
b ~eaK ;
ca se Data F rov lde r .OpЬ ·c :
canJ'! = Dеw Qc:Ib !l\ Соnп е.сtiQIl () ;
br~ak ;
Са$е Da t..a,P ro'Jide.r , Oracle:
СОD П = 'леw OraeleCQnnecti .o n () ;
b:reak;
..cetur·n со пn,;
)
Замечание. Тип Confi g u r at ionMana g er появился в .NEТ 2.0. Не забудьте также устагювить
ссылку на компоновочный блок System. Co nfigu r ati on .dll И указать using ДЛЯ про
странства имен System. Configuratio n .
зовать объекты команд, объекты чтения данных , адаптеры данных и другие тИПЫ,
связанные с обработкой данных. Хотя построить такую библиотеку программно
го кода будет не слишком сложно, для нее потребуется весьма большой по объему
прогрaммный код. 1\ счастью, что касается .NEТ 2.0. добрые люди из Редмонда уже
встроили все неоБХОДИМDе в библиотеки базовых классов .
.кроме тоге, ц.~vr 2.0 каждый поставщик данных от WСlVsщt предлаг?).ет СЩ'-
циальный fQJacc. ПOЛJЧ'ащЩИlЙСЯ:ИЗ буstеrn . .Dа:tа.Соmmоп . DbP.r:oviderFactory, Э'гот
базовый 1~..jIaC:;C оr.rpедел~ет р.яд методов, с IЮмощью жоторъ1Х извлекаlOтсяобъе~ты
данны;,х. спеЦИФИЧНb.Iе дщl дamюто nостcmщика. Во'г список соометст.вуюЩI:IX 'ЧJIе
ЛОВ DbP!'QviderF'a~tory.
кщс вы, наверное. J:J до,ц,умали. вместо попучения исто:ttни1Cа с ПОМОЩЬЮ "жесТ
KO~ эакодировщшой буЩlадЬНОИ СТро;ки. соо-rnетств)"ющу:ю mtФормaщtl9 можно
прОЧU'I'а'ГII из файла *.cOI1fig юmента (аналогично тому , как ЭIfО бъщо сделало в
предьщущем прдм:ере l'1yCOQr:1€ct iо.лFасt'orу). чутъ.ntiзж~:мы с Ш1ЮI TaR И сдедаем.
Но. 1'ах или шraче, СОЗда1! источник своеХ0 IlоставЩИRа дашrых. вы емощете по
JIy.'UfГb объенты (соеДI:IНСЩЩ, команды н т.д.), 'соответствующие ЭТО~ поста:вщцку
Ц<JИНЬЦ:,
944 Часть IV. Программирование с ПОМОЩЬЮ библиотек .NEТ
<DbProviderFactories> в файле
machine,config вашей инсталляции .NET2.0
(заметим, что значение атрибута invariant идентично значению, передаваемому
методу DbProviderFactories .GetFactory ()),
<system,data>
<DbProviderFactori8s>
<add name="Odbc Data Provider"
invariant="System.Data.Odbc"
description=". Net Framework Data Provider for Odbc"
type="System.Data.Odbc.OdbcFactory,
System.Data, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" 1>
<add name="OleDb Data Provider"
invariant="System. Data. OleDb"
description=", Net Framework Data Provider for OlePb"
type="System.Data.OleDb.OleDbFactory,
Sys t em.Data, Version=2.0.0.0, Culture=neutral,
РUbliсКеуТоkеп-Ь77а5с561934еО89" 1>
<add паmе-"ОrасlеСliепt Оаса Provider"
invariant-"Syst8lll. Data, OracleCli8nt"
description=".Net Framework Pata Provider for Oracle"
type="System.Data,OracleClient.OracleC11entFactory,
System.Data,OracleClient, Version=2.0.0.0, Culture=neutral,
PubLicKeyToken=b77a5c561934e089" 1>
<add name="SqlC li en t ОаСа Provider"
invarian t ="SY8tQ , Data. Sqlcli8nt"
descr i pt ion- ", Ne t Framework Da t a Prov1de r for SqlServer"
type-"Sуstеm.Dаtа.SqlСliепt.SqlСl i епt Fа сtоrу, System.Data,
Vеrэiоп=2,О.О. О , Culture=neutral,
l?ublicKeyToken ..b7 7<1Sc5619 34e089" 1>
</DbProviderFactori es>
</system.data>
ЗIМ8ЧIНИ,. Если вы хотиrе использовать МОДВЛЬ источника поставщика AaHHblX ДЛЯ СУБД, не упо
мянутой в Файле machine.config, то знайте, что подобная модель ДЛЯ множества постав
ЩИКОВ данных, I<ак с открытым программным кодом, так и коммерческих, предлагается дис
трибутивом Мопо ,NET (см . главу 1).
cn.GetType() .Fu~~~me);
С;N, Con'n-е'с t iог.Stз;iпg .. cnBtr /
сп. Ореn {'} r
11 C:oaД8JlX8 o&м~a .o,,~,;
DЬСоminaЛd crod = df. Crea teCoromand () j'
Соnз:оlе. Ю' i teLine (HO~ъe.к'!:' 1<ом'андЬ\: (а)" I
Здесь для про верки печатаются полные имена объекта соединения. объекта IЮ
манды и объекта чтения данных. Запустив это приложение. вы обнаружите. что
для чтения данных из таблицы Authors базы данных РиЬв был использован по
ставщик Мiсrоsоft SQL Server (рис. 22.2).
Рис. 22.2. Получение поставщика данных SQL Server с помощью источника постав
щика данных . NEТ 2.0
Далее, если вы измените файл *.config тю<. чтобы в нем для поставщика дан
ных было указано System.Data.OleDb (и соответственно обновите строку соедине
ния), как предлагается ниже:
<configuration>
<appSettings>
<!-- Whicb provider? -->
<add key="provider" value="System.Data.OleDb" />
<!-- Wh1ch connect1on string? -->
<add key="cnStr" value=
"Provider=SQLOLEDB; Dat a Sour ce=loca1host;uid=saipwd=; 1n1t1a1 Catalog=Pubs" / >
</appSettings >
</configuration>
то вы обнаружите. что теперь в фоновом режиме используются типы System.Data.
OleDb (рис. 22.3).
.L
Гла6Q 22. Доступ к базам AaHHblJ( G пQмDщыо ADO.NE:i 947
Н"онеЧF.IО, не имея опыта работы с ADO_NEТ. щ.I можеТе IiMeTh слабое представ
ле~е о ТОМ, что именно де.пi.llOТ оБЪ6КТЫ соединения. 'Команр;ы и чтенин данных.
Но не беспокОЙТесь до поры до времени о детanяx (В конце КОIЩОВ. Б .этой "Главе еще
~е..f\!ало странЩ . .и вам толыш предстоит их прочеСТЬ 1!). На дa1rны'Й момеlfl' важно
ТОЩ;КО ПОНЯТЬ. 'Что в .NEТ2.0 8ПО.lП{е вааможно щ)'строить едицый базовый код. КО
roРl!rИ сможет в деIU:IaраТЙБНОЙ форме принимать раs.щ.D;: I;IоСТавIЦИItов ДЭJ:-Il·n'IX.
Предложенвая. модель оказываеТся очень мощной'. но ВЫ долаш:ы: убеЩJТЬСЯ
в тоМ.' 'ЧТо ~аш баэовый ПРОflРамJИ1I.ЫЙ код ИСПОJ[bэует 'только "Iie 'тИПЫ и MeIТ()ДbI.
которые ОR-2зъmаются: обiЦИМИ ДЛЯ всех поставЩJmОВ . Поэтому при создан:м-и об
щего програм.мнОJ'G кода ограничьте оеБJJ цсцол:ьзоваш,.ем чл.енОВ. npt;длаtаемых
DЬСоnлесt.iG Е . DЬ.Соmm апrd И ,дРугими типами из ЛрОС~0тва имеН5у-stеm.Dа'tа.
C,Q-mm'оГJ. t ,дрyrой CTOpo-Нbl. IШОJП-tе возможно, ЧТО такой. ~Qбобщt"ПНЫЙ" подход ае
ДО~ВОЛИТ исПольэават:ь пекO'ftJрые специфи-reсtще llOЗ~О1ЩiОL'Ти конъ.--ретн.ой СУБД.
так ~O Об.нзательно проверьте работоспособНQСТЬ c03ДiiЦIaeм.OTo вами проrpа.'\1МНО-
1'01ЮД3 В реал:ьных УСЛОВИЯХ.
Злем'ент <connectionStrings>
в рамка..х .NEТ 2.0 файлы конфигурации прИ'lIOЖeИИlI могут определять новый
,злемеltТ, ffa:mаиI:tЫЙ <(:'onrtection-String5>. В к(Д{тексте этото эл~ента вы може
те олределит~ люБQе ч;nсла пар ~eli и значений. которые можно будет uрочи
тать npограммными средетвамц. :ис;польэуя индексатор Сап! igllrаtiопМаi;1@gеr.
CannectionStrings . IЛав!1Ъ11\I1 ПРI;Щ\4)'П.I;еством этого подхода (в QТJlИ'lце О,Т ИС-
l1ОЛЬ30вания ЭЛемента <:appSettings> ИI индексатора сопfigurаtiолМаnаgеr_
AppSet t i пЩ's, ) является то. что в ЭТОМ случае БЫ .можете определять :мt-Jo~eCТBo
СТрок соедП'Нений цля ОДНОГО np:иложении в единообразном стиле.
Для примера обtlOвите свой файл i:\pp. COiJ fi l~ Ta.I(, как ПОК8.Эано ниже (a:rм(,T&~
те. что каждая строка соединеЮ1~ здесь задаетcR атрибутамИ 'паn-lе и ссФnесtiQ!).
String. а не ke.1 и"Vаluе. ЩU\ В случае <appS.et tings».
<CDll f i gч.rа tioI1>
<appSet,t ing:s>
< ! -- \ilhich pro,,-lder? -->
<.a.dd .k6y="provid.er'· vаlое=РSУ$:t.. еm • .Dаtа.SqlСli'е.лt" (>
</ appSetti1'1gs>
948 Часть IV, Программироваtiие с ПОМОЩЬЮ библиотек ,NET
<connectionStrings>
<add пате ="SqlProviderPubs" connecti onString =
"Data Sоurсе=lосаlhоst;uid=sа;рwd=;Iлitiаl Catalog=Pubs" / >
<add пате ="OleDbProviderPubs" connectionString =
"Provider=SQLOLEDB.l;Data Source=localhost;uid=sa:pwd=;Initial Catalog=Pubs" />
</соппесtiопStriпgэ>
</configuration>
Теперь обновите метод Main ().
static void Main(string[] args)
{
Console.WriteLine("*** ИСТОЧНI1КИ п"оставщиков данных ***\п"):
string dp =
ConfigurationManager.AppSettings("prov ider"Ji
string cnStr =
COnfigurationManager.Co пnecti o nStrings[
"SqlProviderPubs"j.ConnectionString;
На этой стадии нашего обсуждения вам уже должно быть ясно, ка}( взаимо
действовать с источником поставщика данных .NET 2.0 (и новым элементом
<connectionStrings> ).
Земечение. Теперь, когда вы понимаете РОЛЬ источнико& поставщиков данных ADO,NEТ, в осталЬ
ных примерах зтой главы будут использоваться типы из System. Data. Sq1client и "жест
ко" закодированные отроки соединений, чтобы Сфокусировать ваше внимание на соответству
ющих более "узких" задачах обсуждения.
Зем.чени •. Если у вас нет копии Microsoft SQL Server, вы можете звгрузить (беоплатную) ко
пию Microsoft SQL Server 2005 Ехргезв Edltlon (http://lab.j!tsdn.micro во f t . coml
express). Хотя зтот инструмент и не обладает абсолютно всеми возможностями полной версии
Microsoft SOL Server, он позволит вам принять преДl1агаемую базу данных Cars, При этом учтите
то, что примеры данной главы соэдаввлись с помощью Мiсrоsоft SQL Server, поэтому для выясне
ния всех проблемных моментов используйте документацию SOL Server 2005 Express Edltlon.
Глава 22. Доступ к базам ,Данных с помощью ADO. NET 949
Чтобы устанDВИТЬ базу дaнJiЫX СЩ'8 на своей .мaunmе. RaЧЮlте е запуска yт~
ЛИТI:;I Query AnaJyzer (Анвли;щтор запросов). Пdставляемой в paMRax SQL Server.
Сое,циннтесь со своей. мaI1ЩНой и crПЩОЙ're фaй.Ir Са rs .БЧ1. npе.цлar3.емыЙ в папке с
.исхоД1lЫМ кодом примеров дlIЯ данной т.лавы. Перед 'Гем JШВ ВЫШJЛНИТЪ cцeHap~.
убе,цитесь 11 том. ЧТО путь,уtЩЗa.щ:IblЙ В SQL-фaй.1iе. соотвe-rстзует вашей ЦНС'1!ЗJ1.
ляции М1сrosоft SQL Server. Ес;:л:и f{еобходимо, отредактируйте сл.едующие стрщщ
(вьщеленные полужирны:м шрифтом).
1
950 Часть IV. Программирование с помощью библиотек .NET
правой кноmюй мыши на узле Data Соппесtiопs (Связь с данными) и выберите Add
Соппесtiоп (Добавить соединение) из контекстного меню. В появившемся диалого
вом окне выберите в качестве источника данных Мiсrоsоft SgL Server. В следую
щем диалотовом окне выберите имя своей машины из раСКРЫВaIOщегося списка
Serveг Name (имя сервера) или просто укажите localhost, а также укажите правиль
ную информацию для входа в систему. Наконец. выберите базу данных Cars из
раСl<рываlОщегося списка Select ог епtег а database пате (Выбрать или ввести имя
базы данных). рис. 22.5.
После завершения описанной процедУРЫ, в рамках подцерена Data Соппесtiопs
должен появиться узел ДЛЯ Cars. Обратите внимание на то. что здесь же можно
увидеть и записи любой таблицы. если щелкнуть на ее имени правой кнопкой
мыши и выбрать Show ТаЫе Data (ПОRaзать данные таблицы) из nоявившегося КОН
текстното меню (рис. 22.6).
o..ta~cr:
I I-ta_oso_
L -_· ft_5Q.:...-Serv_;"-,-~-,--
.",;'=----___ .-J (Qw1ge... I
o u...1:l)ndow. дuthl!nfica_
1__. - а '\!i!11II><sR
G Sel!!ct oron!l!r '. _.-. пате: .. __ __ .
._ ---~ --~
Ii!
I~· .. I
,-~ -'--'- -'- . ~--;:=:=,~==:;
[ !б! Сoпnedion I еж I[ CiIraI ]
J],-<~; ,•.!~}~,,,,~
';;' :.t:i .NfЭ CМni!<:tiO<i!.
';iJj ~~~ o.,,,,:ObJ:;
r..: ~ "~':~I
- -"fJ ~ ·,iI!P,3@#i
.4dd"li'~ r..ыe
.. .1! ~""'ffJ~ '
~ ]! О,""," l' ..\diJ *,,,Ttigger i
..:;:JV",,,. I ~."Quefy I
, 1 ..::;J $wro ~~.
cll1'ss P r .Qgra'm
1
st.. tic v ,.)id Main (Stl':Lng [] Qr-gs)
1
952 Часть IV, Программирование с помощью библиотек ,NET
cn.ConnectionString ~
"uid=sa;pwd~;Initial Catalog=Cars; Data Source~(local)";
сn.Ореп ();
1/ Цик.п по ре~УШотатам.
while (myDataReader.Read())
(
Сопsоlе.WritеLiпе("-> Марка - { О }, имя - (l), Цв е т - ( 2).",
myDataReader["Make"J .ToString() .Trim(),
myDataReader["PetName"] .ToString() .Trim(),
myDataReader["Color"j .ToString() .T rim ());
Замечание. Чтобы узнать больше о парах имен и значений для той конкретной СУБД, которую
иопользуете вы, в документвции ,NEТ Framework 2.0 SDK найдите и прочитайте описание свой
ства ConnectionString объеl<та соединения для вsшего поставщика данных.
1
Глава 22. Доступ к базам J1aWHbI)\ с ГlОМОЩI>IО ADO.NEТ 953
объект соеДИEl.ени.н npедлаг.аe'J' еще целый рид \]Ленов, хот.оРБJе позволдют IЩ
проить ДОJ]ОЛНН'I€'пIЫU;Iе пара:метры соеДJПIеgия. НЩIример. та.1Ще, как BP~M:U
ожидания R С:ВОЙСТВЗ тран3а1ЩИН. описaI:tия: }leKOT@pbJX Ч.1lенов базового цласса
DЬGоппесti оn предлarаютс.н в табл. 22,6,
Cha11g€Data.r~a6e (.) Метод, используемый дпя CMe~1 бsзы данн'Ых пр!/! открытоМ СОЕ1Дl'1неr~ии
Data 5.о '!;] !'се СвойсТlШ, ещ)бща,ющее информацию о месте размещения базы ~H~
НЫХ, ИСПОJ1ьзуемоVt Объектом о::оединеtlия
в этом фрю'менте программного НQЩ1 обратще ВЮD4а:ние на ТО. что теперь объ·
ект соецинении передается в в}Ще napaмe-rpa BOBO~ .вспомогатеm.нoму статйче
СКnМУ метrщy Sh.оwСоппесt.iодst..аt;uэ О ·КIП:1.CGR P1;ogra.m, рe.am.fзованиому 'ta2(, юн(
показcuю ниже.
,.
1
954 Часть IV. Программирование с помощью библиотек .NET
ShowConnectionStatus(cn);
Глава 22. ДОСТУП к базвf.1 дамных о ПОМОЩЬЮ ADO.NEТ 95'5'
в ЭТОМ варианте IlpОГРil1\1:ЩIOГО ItClда созд<!.ется ЭRЗeмI1JlЩJ Sql С опп е с t i о t! -
StrlnqE!\Jil ,d e r. устанавливаются сооrrвеТСТВyJOщие свойrn:вa и с ПQМОЩЪЮ свои
стваGо rl11:есtiолStr-.iЛJ} получается внутреюыm строн, а.. Заметьте. чтоздесъ ис
пользуется HOHcrгpPCТ0p типа, задан:ныi} тю умолчаНИю. Можно также (юздать
экземпляр объекта DОСТРОJ,iтеля строк со~;ципеНИJI дпн пестав1ЦИКЗ ,данных , аере
дав уже суще.ствуюIЦyIO СТРOl<у соединеrщ:д в качестве исХодной (от.о може'1' шщ-
3.атъсн пОЛез.IIо тогда. ноrда соответствующие значения считываютея динам:иЧ~СlI'oИ
из файла app.config). ПолучИl3 ТЩ(ОЙ 06ъeK'F!i' началь.нымИ. СТРОЬ."ОВblМИ даmtЬJ.1yЩ,
в.&i можете измеНИIЪ пары Щl.fеи и ~наче}ЦiЙ с помощью соответстцующих СВОЙС"I;В,
ВaIIpИМер:
Член Описание
Замечание. Позже в этой главе будет показано, что в .NEТ 2.0 у объекта Sqlcommand появилось
несколько дополнительных членов, упрощающих задачу всинхронного взаимодействия с база
ми данных.
~ла~а 2г. доmп k базаМ данЫЫХ с ПОМОЩЬЮ ADQ.NEТ 957
Инденсатор объента чтения данных перегружен. чтобы ему можно быдо пере
дать либо строку (представляющую имя столбца). либо целое число (соответству
ющее порядковому номеру столбца). Поэтому вы можете немного "подчистить· со
ответствующий фрагмент программы (избавившись от необходимости печатания
имен) и использовать вариант. показанный ниже (обратите внимание на использо
вание свойства F'ie1dCount).
w!-,i 1е (туОа taReader .. Read () )
{
Conso1e.WriteLine(n***** Запись *****");
for (int i = О; i < myDataReader.FieldCount; i++)
{
conso1e. WriteLine (" {О) = {l} ",
myDataReader.GetName(i),
myDataReader.GetVall1e(i) .ToString() .Trim());
Console.WriteLine() ;
После Еомпи.iIЯЦИИ И запуска зтого проекта вы должны увидеть список всех ав
томоБИiIей из таблицы Inventory базы данных Сагв (рис. 22.7).
striТJg lh'2S,QL ~ "Select " From 1I1ve.n:tory; Selei:t. -;- fTom Cus'tomers";
do
(
whiie(l1\~DataReader.R~ad(»)
{
11 Чтsнке ИВфQрмац5Щ U'ехущеrо ваб'ора резузn.~а'1'оа.
}
'whiJ е (J1tybataReader. NextResult ()) :
Теперь вы ДОЛЖНЫ ,знать болыnе о воаМОЖНЩ.'ТЯХ объектов "пения )),aIiliPIX. Э~
объекты пре.дла:гaIOТ н Другие В03МQЖЦОСТИ, о щrтoрb.D!< ;щесъ Щ' ynоминалоеь (на'
цример, ВЪ1I1O'Шiение скалярных и о,д1щстрочныxацроG{ш),' СЙО1:ветствующие под
РОБНОС"ГИ можно найти в ДOl~ументации .NEТ Framework 2.0 SDK
• Q- выйти из проrраммы.
Showlnstructions();
do
(
Сопsоlе.Writе("Введите команду: ");
userCommand = Console.ReadLine() I
Console.WriteLine():
switch (usеrСоmmапd.ТоИрреr())
{
case "1":
InsertNewCar(cn) :
break;
case "И";
ИрdаtеСаrРеtNаmе(сп) :
break;
case "О";
DeleteCar(cn):
break;
case "L":
ListlnventorY(Cnj;
break;
case "5":
Showlnstructions();
break;
case "Q":
userDone true;
break;
1
Гп&вз 22, Аоет~п к базам данных с ПОМОЩЬЮ AOO.NEТ 96'1
default.:
Соnэоl е. w:t.i teL.ine ("ЫеI(ФрреК'I'RЬ1е .1iIаъ"НЫе J Вве:цит!;!! 'nРУТ'И€.") ;
Ьгеак;
} while (!uэе.rDОIJе};
on.Close{);
}
Удаление записей
Удалить существующую запись так же просто. как и вставить новую. Но, в от
личие от программного кода для IлsеrtNеwСаr(), ниже демонстрируется важная
возможность применения try / catch ДЛЯ обработки попытки удаления автомобиля,
используемого в настояIЦИЙ момент в процессе оформления заказа для покупателя
из таблицы Customers (сама эта таблица будет рассмотрена в ЭТОЙ главе позже),
Обновление записей
Если БЫ разобралt1Сl1 с ПРОГРClJ\1МНЫМ'1\ОДОМ ,ДЛИ nel~teCar'( i ~ ln!S,er tNe-wСаrО.
то и IJPОI'рС1ММН14Й КОД ДЛЯ Upddte ~;: arPetName () :не будет ДЛ'Я Ba~ сложным (эдесь
ДJJfl цро.СТОТ,bl .допrnа try/catc:h тоже "Исключеfiа) ,
priV'.a,t e st.<i!'tlс:.IГDid 'U,рdаt:еСа.r:Ре'сN'iiше (SqlСоl1t.1есtiол crj)
!
// nO~учениа нонера .~~ P.mI ~0.цифnk8.ЦИИ и вв,о,ц НОВОГО .lВUiШИII'.
СОIlSlЭl",. 'Writе \ "В ве'ците номер !Ji4аши1'!Ы.дJ"lЯ МО.дИфUlкаiJ,.ни : ");
5'!.!' i ng 'пеwРе~Namе ~ п п ;
/ / Обl\lOВJ.lе.виа ЗiЦПfСJ!.
slriйg sч1 =
st :ri ng.FЬrUJбt("Орdаtе Im!~ntljry Set Fеt.ЩШJе='!ОI, · Where CarID=',{1} "',
t1~wРеtNа.ше, .ca.r'I'olJpda't.e) i SqlСоmшаnd сшd = 'rJE'W SqlCt5m:rrJand (sgl, СП);
t~,d . Е...ХЕ:f:litЕNО·(jQпе:rу () ;
}
Свойство Описание
DbType Читает или записывает иНформацию о "родном" типе данных для источни
ка данных, представленную в виде соответствующего типа данных CLR
Direction Читает или записывает значение, указывающее направление потока ДЛЯ
данного параметра (только ввод, только вывод, двунаправленное движе
ние, предусмотренное возвращение значения)
IsNullable Читает или записывает значение, являющееся индикатором того, что па
раметр допускает значения null
ParameterName Читает или устанавливает имя DbParameter
Size Читает или устанавливает максимальный размер данных параметра
себя подобно тицичной фующии. С той очевидной разницей, что размещается она
в хранилище данных, а не в ДIlоичном рабочем объекте.
Замечание. ХОП1 обсуждение соответствующей темы в этой главе не предполагаеТСf1, CaMaf1 новая
версия Мiсrosоft SQL Server (2005) включает в себя CLR,xOCT! Таким образом, хранимые проце
дуры (и другие атомарные единицы базы данных) могут создаваться с помощью управляемых
языков (например, С#), а не только с помощью традиционного языка SQL. Подробности можно
наЙТИ на страницах http://www . microsoft. сот/ sql/20 О 5.
// Входной параметр.
SqlParameter' ратат = new SqlParameter () ;
param.ParameterName = "@carID";
param.SqlDbType = SqlDbType.lnt;
param.Value = carID;
param.Direction = ParameterDirection.lnputi
Глава 22. ДCJстул к '6}ааам Aal1HblX с nОМОЩЫ!) АОО. NEТ 967
сщQ. Fiaramet$rs. Ad.d (раташ) ;
/I ВlilXо,цвой параиеorp.
p.aram = new Sqll'",r.ёJrneb=r () ;
раrал).Рэrаmе-t.еrЫamе = "Щр.еtNаше"1
param.SqlDhType = Si;jlDbType.Chд;r;
Fс,rащ.Sizе = 20 ;
par-ё1д1.IJirесt i оn = }'aL:arneterD iTectiori, 01.1tJ>,'ot:
cmd . I"ararneters. Add (ра ram) ;
1/ 1IъПI'Cinиeuиe ~Р~ЙD;pацедУРloI.
c:rn,:l. EKetIJ teNonQu e ту .() ;
ОбраТft"Ге :внИМание на то, "<fI'O свойство Di recti ВЛ. 'Объекта параметра позволя
ет указать з:ходnые и выходные параметры. ПО заверщении БЬ13ова хранимой про
цедуры с помощью Exe.cuteNQnQuery () вы можете lЩЛУЧИТЬ эна'reЮrе ВЫХОДIJl)fО
параметрз, обраТ.fПЩJИСЬ к :кощ:rе:кЦЮ'I' параметровобъекта :команды . На рис. 22.9
II<lliаgаи оД}'ш иЗ БО3МОJl\.'нык вариантов тестового зацуека программы.
'1
,
968 Часть IV. Программирование с помощью библиотек .NET
Console.WriteLine();
Глава ~2 . Доступ 1( -базам дafHfblX с помощью доо. NEТ 969
IJ Ее.. ~oonoso! Въш:ОЦКeJ!И8 циq&по ре!lУ.иь'l'.&'l'UI
1/ с ~ОМОIЦЬИ) обrъeX'l'A Ч'l'$НИИ ~i!lBвpjr.
SqlDataRe~cler ,royDd:taR~adR:r =
mYCQmmanci. E,ndE>te'GUteReader (,i t.fAsyoCfi) ;
while {шуDаtаRеаdеr. Read (j )
{
СdП501",. Wri teLifJe ("-> марка - {[)}, наз-вЗ-ние - (,1 J, uвe~ - J:2}.",
шу'DаtаRеаder r "М'аkг" ] . ToStriug(.) ,Trim () .,
mYDiiitE\:F..eade!' [·"PetName"] .'1'o,S tring(} • T.rl.m () г
myDa baRead~J; [ "СФ l,o·r" ] • Тоs-t:tiпg () . Tr1ro (J D;
mY:Di!1taReade][. Сlс>.Э~ () i
1
970 Часть IV. Программирование с помоЩью библиотек .NET
Приложение-клиент
r г- -""--
.....
i'--- ...--' ..., 1'--
DataSet .J Адаптер данных База данных
~
'- ---
Рис. 22.10. Объекты адаптера данных передают объекты DataSet кли
енту и возвращают их обратно базе данных
Роль DataSet
Упрощенно говоря. DataSet является представлением внешних Данных в па
мяТи. Более точно. DataSe.t представляет собой туш класса. поддер:щивающий три
внутренние строго типизованные коллекции (рис. 22. 11).
DataSet
IDаtаТаblеСоllесtiоп
I DаtаRеlаtiопСоllесtiоп
I Рrореrtусоllесtiоп
Рис.22.11. "Анатомия" DataSet
Члены DataSet
Перед пот руже1I1!lемв миогоч:исленвые детали програ:м.мирования ,иавай,'е
расемотри:м Н'абор базовых ч:iтеновDа:tаs-еt. Кроме свойств Tables. Relations и
Ехtелd",-dPIт\р.егl.i.€s. в табл. 22:9 опИсаны некот{JрыIe другие интересные свой
C'J"Вa.
СвоАство О.lисание
EJ1 forc",CoJ1:st l'ёJ iлt $ ПОЛУ'Н1ет ИЛИ устаНЭВ'i1ивает значение, являющееся иt;i·ДИI':aТОРО~(
I-lеобхоДPlМОctJ.f ТlРIIIМеtl8НИЯ заданных ограничений при любой
Qnерации а6новлеН(/,I~1
HasErLors Получает ЗН8'tение, ЯВЛЯ1Dщеес!\ \IIIЩИКЗТОРОМ НW1ИЧИЯ ОlJjибок В
люtJой 1113 строк обмктое Dato!Ta1:"le дпя об1>еJ<та I)E(taSet
Новое GВОЙСiвО .NET 2.0. позволяющее указать, каК должНа 81'i1пш1-
~rЯ1ЪСЯ Сериа.лиза,ция D.atakt (,ВДВQИЧНОМ .f1ли )(МL-формате) для
!Злqя удаленного взаИМQдеи(;твYlЯ .NEl
Методы Описа"ие
Accept.Changes () Фиксирует все изменения, сделанные в данном объекте DataSet С
момента его загрузки или последнего выЗова AcceptChanges ()
Clear() Выполняет полную ОLIИСТКУ данных DataSet путем удаления всех
строк в каждом объекте Dat.aTable
Clone () Клонирует структуру DataSet, включая все объекты DataTable,
а также все отношения и ограНИLlения
Объект D,зtа$еt без DбъеКТDВ DataT'a ble чем~то рanоМ'инает рабочую н:еде.m{l
без ~ьIXОДНЫХ. Паэтому слеД}''10щеи нашей эадачей будет pa(;cмoтpeНl,e ВFiYтр~nНей
стр}"Кi!ypЫ Dat aTable., начи:наи с типа DataColumn.
Работа с DataCo,lumn
Тип Оа t а Со l u :ro 11 nP~ДС'rа1lляет отдельн:ый столбец 11 пределах Data;Tab.le.
Вообще говоря. Набор всех ТИllQВ "I)ataColaw:n в границах дaннnгo типа DataTa ble
представляет собой струкгуру т.абn:ицы. HaдpfI,Мep. чтобы преДстави.тЬ таБЛИЦ,V
1nventory базы данных Сагз . .вы ДОД.ЩRPI ~@Здать, четыретиnэ IJa taC'oll Шllд. по ОДНО-
М)' для GaЖдого столбца этой таблицы (CarlD. Mak~. Соl0r- и PetN"i3.IiIE). После созда
ния 6бъеI{Т()В Ii),a ti:iCoI L1l'!\fI они добавл:я:ютсSJ в коллекцию столбцов типа Dat.aTable
(спомощыо с:войства Co lumps).
ИМея определенну'JP подготовку в области Т~ИИ реляциQнных баз дaI-шых.. вы
ДОЛЖНЫ знать. Ч1'О €толбцу 11 таблице дзl;пIых МоЖНО назначить набор orpaн:ичеIOtЙ
(например. иcnОлъ:.юватъ L'1'олбец 'в Щl.честве первичного , ЮJЮча. задать звачение
ло умолчаnиro . потребовать. чтобы информацнл в столбце была доступна TOJIЬКO
ДЛЯ чтений и т. д.). Также K~ столбец в табmще Д~J1Жеи соотвe-rствовать за
данному Д.JIЯ иеrо типу даннЬРС. Например. струнтура таблицы Inventory требует.
чтобызначеНйя столБUа саrID ' Былиедыми числами. а 'ЗНачения Маке. Colo.1" й
PetN'ame - наборами симвоJ.IРВ., Класс Dаtаl,JQl шnn имеет множество евоЙетв. ко
торые ПОЗВОЛЯ'ют ВЫПOJUmть <:оотве~ствущщие настройки . Оhисания осповu.ьtx
своЙcr.в 9roго типа прx:mеде:ньJ F.I табл. 22.1 J.
Allio-wDВNП.ll Индикатор' того, LITO стр.ока в ЭТОМ С;ТDлоЦе (IЛ(}же;т ОOiO,ержа,ть Зliа'lБ!'iие
null. ЗначеtlИВМ ПQVМD:l'lat1ию' является true
Capt lOn Llиraет ИЛИ' устанавливает текст заголовка\ который должен QТo6pa
жаТЬGRДЛЯ Aa~IHorQ столбца (наnрймв'р, текст. I(()ТQР~IЙ увидит КО~lеч
ный" полЬЗ'авателЬ. в DataGrid'Ji e w)
COlu:m1".мappin g Определяет представление Da t.aC olufl1n I!1РИ сохранеliИИ
p at aSet
в sli1AeXML-Аокумеtiта с помоЩью мето,о.а DataSet .W.-.i·tеХml О
Со lа!i\R Nаш е Читает или, уtтвflaВЛИваSoт имя столбца в j(Оfl~IЩИИ Colblmr'ls (Т, 6 . -его
преДGТ<i!~nен'Ж! -в Dat. aTabJ.e). Еоли не ус;rановить 'Соl.UIIIпNam е Я8НО,
знаqеl'lием ПО умолчанию будет CollolffiD с номером c:rолбца
(Т.е. C61umnl, Сdlщаn2. соlumnз и Т,Д.)
[16 .fau HVi'11ue ЧИ'тает ИЛи усrаf.tаВЛИ1!rIе-т ЗНQiеl'Ме, "OTO'P~ ДОлЖНО лрИriисываТI;ЮЯ
по УМО:Л'18НИЮ .n,.lЯ щ\ННDГО столбца ПРИ вставке HOB~)( crpOIl".
Это эwаЧ€l1ие используется TOr,na. lФiДЗ' не УКi.'lЭЩ10 ИЩJе
974 Часть IV. Программирование с помощью библиотек .NET
Создание DataColumn
Чтобы продолжить рабату с проектом SimpleDataS e t (и привести пример ис
пользования DataCo l umn ), пр едполажим. чтО' нам нужна представить столбцы
таблицы Inventory. Учитывая та. что столбец Са rI D явля ется первичным ЮDочам
таблицы. мы сделаем абъект DataCo1umn доступным толы оо для чтения, с ограни
чением уцикальнасти и не ДОПУСI<ающим ввада зна чений пи 1 1 (испальзуя свайства
Re a dOnly, Un ique и Al l oWDBNu ll ). Обнавите метад Mai n () так. чтобы постраить
четыре объекта DataColurnn .
D аtа Соlumл ca rM ake Co l umn = new DаtаС оl urtш (" Make " I typ eof (s t ri ng ) );
DataColl1mn car Col o r Co 1 umn = new DаtаС о l шnп ( " Color ",
typeof(str i n g )) ;
Dа t а Соlumл c a r Pe tNameColumn = new Da taCo 1'l1mn (" Pe tN ame",
t ypeof(s t r ing ));
carPetN ame Co,Lumn . Capt i on = "Н а зван ие ";
Глава 22. До[;туп К базам дз~Iныx G ГIОМОЩЫО APO.N~ 975
Работа с DataRow
Вы видели. что коллекция объектов Data Co lumn представляет структуру
DataTabl e . Коллекция типов DataRo w npедставляет факгические данные таблицы .
Поэтому если у вас в таблице Iпveпtшу базы данных Cars содержится 20 записей,
вы можете представить эти записи с помощью 20 типов DataRow. Используя чле
НЪ! класса DataRow, можно вставлять, удалять оценивать и перемещать эначения
ЧЛ8.НЫ описание
DataTable. Предположим, например. что нам нужно ВСТавить две строки в табли
цуlnventory. Метод Da taTable. NewRow () позволяет ДОбавить очередную строку в
таблицу. а затем вы можете добавить в каждый столбец новые данные с помощью
индексатора типа, как показано ниже.
Свойство DataRow.RowState
СвойетвоFcwSt:ate QI<a3blВается полезным тогда, KOrдa необходимо прогрщ.rмно
идентифацировать на.бор всех 'Строк 'в таб.лицt:'. которая • .шшрllМ~р., была изм:еIiе
на. ТОЛЬКО чТо Gоздан.а ит.Д. Это СВойство 1Vfо.жет прИRИ.Мa'I'Ь любое знэ.qеЮifе из
перечнн DataRowState. Описания этих аначений цреДJIагаются: в табл. 22.13.
3наченке Оnмсание
!)е Leted Стрtжа была удалена с ПQМОЦlЬЮ метода Delete О om.e'qa D<!t.af<.o:w
!Jetacl1e<i СтроКЕ! -была создана, но неЯБляется 'IВetью коллекции Da tаЯОWСQ11 ect.iop,
Qfi'i:>6trr ba:taR.o'", находится в· этом С0СТIЖ!fИIII после своего соЗ'дан\l!11 ДО ТОГО .
кэк будет доБС!ВЛ8Н " коллек!:),ИИ (илk1 же П(J)Щlе уд;ItЛения этого объекта 143 ко.п,
лекции)
Modifie,d Строка была !Азмеkена. 1-10 метод AcceptC,haflges (:) не ВЫЗЫ8алt~
t1neh.ang,ed Стока не измеНялаCJ> со вреМеНи n-bCJIeДHeгo вызова: AcceptC!'mnge-s ()
Как виДИ'Ге , Dat a Row в ADO.NET является достаточно "сообразительным " для
того. чтобы контролировать текущее ПОЛОЖение вещей. Поэтому , имея DataTabl e ,
вы можете выяснить, какие строки были изменены. Эта особенность Data Set очень
важна, поскольку именно она при отправке обновленной информации в хранили
ще данных позволяет отправлять только измененные данные .
Работа с DataTabIe
ТИпData T a ble определяет большое количество членов, многие из которых по
именам и возможностям идентичны членам Dat a Set. В табл. 22.14 предлагаются
описания основных свойств тшra Dat aTable, за исключением Ro ws и Co l umns .
С а s e Se nsi t ive Индикатор необходимости учета регистра символов при сравнен и и CTPOk
в пределах таблицы. Значением по умолчанию является fa l se (ложь)
Ch i l dRe lat i ons Возвращае т коллекцию дочерних отношений ДЛЯ данного объекта
DataTable (если таковые имеются)
Mi ni mum Capacity Читает или устанавливает значение ДЛЯ начального числа стро к данной
таблицы (это знвчение по умолчанию равно 25)
Pa r e ntRe lations Возвращает коллекцию родительс к их отношений ДЛЯ данного объекта
Dat aTable
Prima r yKey Читает или устанавливает массив столбцов , функционирующих в качестве
первичных ключей для таблицы данных
Re moti ng F'ormat Позволяет определить , как объект Data Se t должен выполнять С'ериализа·
цию соответствующего содержимого (в двоичном или ХМL-формате) ДЛЯ
слоя удаленного взаимодействия . NEТ. Это свойство появило с ь в . NEТ 2.0
ТаЫ е Ы ат е Читает или устанавливает имя таблицы. Это же свойство может быть ука
зано в качестве параметра конструктора
Б нашем примере мы установим свойство Pr ima r y Key типа DataTa ble равным
объекту c ar I DCo lumn типа Dat a Co l u mn .
s ta tic void Ma in(st ri ng [ ] a rg s )
I
Метод "'r'i,n.t DataSet !) просто вьтодняет ЦJЦtII во воем Da,t aTabl.e из Da.taSe,t.
печат'"clЯ им.еыа ётолБЦОБ и значения строк с помощr;.ю 'инденсатора типа.
:Соns,olе '. Wri te L·:h ae -СУ' \ п--- - - - ---~ ---- - .---- ------- ---- -" ) ;
11 !Шво;ц: DataTable .•
f o.r (i.пt curRClw = О; СЦ'rRоw < dt.Rоw,S.СОlшt; eurRQw+-+)
i
for (iлt ситСоl = О; c1;J:t;Col < dt.Со1UJIшs.СОtJпt; CLlTColH)
i
COrisQle.Write (r,;lt.Fc;).w-s [curRowJ [cu.rCG1] .ToString() ... "\t");
]
С o.rj $01 е ..Writ.eLl n.e (.) :
}
Console.WriteLine();
P rintTable(carSInventoryDS.Tables["Inventory"]);
Если oTRpыьь caxpaн~ файл car5DataSet .xml, вы увцците. ЧТО J3 нем пред
атЭВдеНы все столбцы');аб;mц-ыI. -заоодцрrщанные в виде XМL-элементов,
J
982 Часть IV. Программирование с помощью библиотек .NET
< ?xml v ersio o=" l . O" s t an·d alone=" yes " ?>
<Car_x0020 Inven~ o IY>
<Inventory CarID="O" >
<Make > BМW </ Make>
<Со l о r > че р ньri1 </ Соlоr >
<PetNa me>Haml et <!PetNa me>
</ Ir1ventory>
<l n ve n tor y CarID="l " >
< Маке >Ба аЬ</Ма ке >
<Colo r >KpacHbm<!Co loI>
<PetN ame>Sea Bre ez e</Pe t Name >
</Inven t o ry>
<!С ат хОО20 Inven to ry >
розоеый
I свет /10'з~еный
Замечание. Для представления реляционных баз данных в .NET 2.0 злемент управления
DataGridView считается наиболее "предпочтительным", однако остается доступным и уста
ревший элемент управления .NEТ 1.Х DataGrid.
РnbНс Mainf:D.rm ()
t
1 ni t,i alizeCompOn€'rit '(); Сел't' еГТ0&сгеел() I
/I ЗаnолнеlЩQ оnщ:ка.
i1.r'IheC'a r'Si . ~i1,dd (пеw Са Сl " Ch.iJckyn, "BMW", "эел",'нЬ!Й"» i
,сП Т hеС а l:Э . .1'>\dd .( r!E'W Са r I ,\ Т iny", "Y ag,o'!, "ав,т.т") J ;
в r'J.'he Са r s . ~dfl (ое..., Са r 'С"", "Зеер" I "к о ри'ЧневртЙ"»;
a rl1heCaxs.Ad.d(Гi8W CarC"PaiE lnci)1ce1"', "('.вrа:vад", "РОз6ВЫТ)Г')!;
а;тТnеса т в. Add (new Ca .r ("Fred", "вм.w·', "светло-з.еленыИ") .;
a:cThe.cars .Add~new Саи: ("Buddha" ( "Bмw· l , "черrrЬ!Й") J ;
атТоеСа r:s . /l..d:dl riew Са!" ( "Ме 1 ", " р i.rebird rт, "крас:нъ.tй "')) ;
BTTh,eCars. АсИ (new Сет ("'S'ara'11" r "Со1 t ", "черный",) J :
}
J
984 Часть IV. Программирование с помощью библиотек .NEТ
\
,Меssа:'gе-Вщt, Srюw (ех ,Меэsаgе) )
J
986 Часть IV. Программирование G помощью библиотек .NET
белый
)Jeep KOPl-IчнееЬIс;.
Caravan РО3061;tЖ
ОК
11 COp~'pOB!tano PetName.
шаКеБ = i.nvel1t:oTyTabl е . Select, (fi1 t<llStr, "'р.tNаш.е" ) ;
Чтобы ynИдезъ реаулыгаты в ниr:-хощпцем ПОР,IЩКе, ~Ь!зовите Select; (). как по
казана ниже.
06НQвлен",е строк
Еще одной ЩJерацией. RОТОРУЮ БЫ должны о.своитъ" явлв:ется. изменеиие значе.
ни.й еущесТllУЮщей в Dаtаt:raJэlе строки. С ~п.оЙ' це:лыо можно, например; с.ндчала
с DО.\lllОIЦPЩ метода Sel(O'ct (} П()]I)"'ЩТЪ строку, еоо'ГВеТСТву1ОЩУЮ нмеющемуся кри
терию фИJ.Iьтра. Имея соот;ветствующи:й объект 'Qa·t.aRow, вы м.ожю:е 'СОQтветсrnую
щим образом его измеЩilТ,q, ПредцО"л()~м, ЧТО в форме есть RНопка (nrn Бuttоп}.
при щел<те. н.а которой ВЫIЮЛН.J'\.ется РОИСR ТeJЧ стр<т В объекте .DataTable. для Кб
TOPЪU!; Мак,: равно BМW. Идентифицировав ~11И '3лементы. Iiы изменяете знаЧtнnrе
М а ke с EMW н.а' Со1 t.
988 Часть IV. Программирование о помощью библиотек .NEТ
11 ПОС'1'роение фИЛЬ'1'ра.
string filterStr = "Ma]<e='BMW''';
string strMake = nul1;
Класс DataRow преДJIarает методы BeginEdit (). EndEdit () и CancelEdi t (). ко
торые позволяют редактировать содержимое строки. временно приостанавливая
Вы, конечно, можете вызывать эти методы для данного DataRow и вручную,
НО они вызываются автоматически при редактировании элемента DataGridView,
связанного с DataTable. Например. при выборе строки в DataGridView эта строка
автоматически переводится в режим редактирования. А при перемещении фокуса
ввода в новую CTP0Ity автоматически вызывается EndEdit ().
Глпва 22. :ЦОС1"упlC базам д.аflНbt.JC ",noмощью ADO.NET 989
i --
коричневьJЙ
т раэ~ый I Pдlin 11
t;ee1 lIо-зеl1еныi:i Fred .g
•
•
Рис. 22.17. Представление отф~льтрованных данных
Член.,. Описание
SelectCommand Задают SQL-комэнды, которые будут отправлены хранилищу данных при
InsertCommand вызове метода Fill () или Update ()
UpdateCommand
DeleteCommand
FillO Заполняет данную таблицу в DataSet некоторым набором записей, за
висящим от заданного объектом команды значения SelectCommand
Update () Обновляет DataTable, используя объекты команд из свойств
IпsеrtСоmшапd, UpdateCommand или DeleteCom.mand. Точная ко
манда, которая при этом выполняется, зависиТ от значения RowState
для данного DataRow в данном объекте DataTable (данного DataSet)
[пава 22. Доступ ~ баЗl1М даНkЫХ с ПОМОЩЬЮ ADO, NEJ 991
в следующих примерах :не забывайте о' т.ом. что объекты aд~nTepa данных
упрaВJ1sпот соответствующим соединением с базой дaIfНЫ:X за ваС. та}!; ЧТО вам не
nРИДf'1'СЯ nВИQ 01J'РЫ1ЩТЬ или ЩI.НрывGIТЬ сеанс связи с СУБД, Тем 'Не :менее. ~aM все
равно нужно n.редостаЩIТЬ адаптеру да иных дclkтвнтелъный обыжr аQед11Н~ИИR
ИJЩ. в вцде аргумента fюнст:руктора. ~рсшу соединения (которая будет ИСl'Щl!ЪЭО
Ba:rъC8 ддя DОСТРЩ~1Щ.!l в;цутре.ннето OOЪeRТa соединения).
11 Orобра.~ СО;Qержимоro.
Prirlt'.DataS'et (myV.s};
0бра1'иrrе внимание 1Ia то. что ададтер дaннъrx создается с указанием SQL-
'Оператора Selec t. Это 31rn:ченuе будет ислоль~оватъt:.я: фШ внутреннего постро
еш,ы! объекта команды. которую за.те,м МОЖF.\Q будет по:rry"iИТЬ, выбрав (;вой.ство
SelectCQ!11m.and. Далее. заметьте, Ч1'Q метод Fill 1, получает экземп,ляр типа
D.ata5~it и неоБЖJa,теЛhНое стрОВQJюе ИМЯ. КО'Г0р!;)е будет использоваться пря УсТа
lювке свойmватаыlNаmеe нового Qбъекта [1ataTaы1e (если вы не у.кажете имя т-а
блицы. адзnrrер данных ИCI10дьзуетдrЦ'lтабщщьr R,lМНTableJ.
JUili и ,следует ожидать. при передаче Da'taS~t методу Е'!" i-r,tDаtаSе"t, () tpеали
:,юванному И этой rлаве pa1!e~} будет подучен список .Jloex стрщr та,бщщы lnvent,ory
6айы д;лпtых Cars (рис . 22. i8),
при желании вы можете использовать эту коллекцию ДЛЯ того. чтобы инфор
мировать DataTable о "дисплейных именах" . которые должны использоваться
при выводе содержимого. Предположим. например. что вы хотите отобразить
имя l n v en tory. используемое для таблицы в рамках СУБД , в дисплейное имя
Ассортимент. Кроме того. предположим, что вы хотите отобразить имя столбца
CarID в виде Но мер. а имя столбца PetName - в виде Название . для этого в объект
адаптера данных перед вызовом метода Fi 11 () добавьте следующий npогрaммный
код (и не забудьте указать usirlg для пространства имен System.Data.C omm.on ).
static void Main(string[] args)
}
., .
Обрати.те внимание и:на то, что методы Li g t 1 nvento:t)' (.), DeleteCa r ().
Uрdаt.еСд.I'РеНiamе (:) и In.s.ertNewCar(') ТaRже бbIЛИ изменены (; тем, чтобы OlЦI
могли ПРИНII'l'Ъ Sч1 DаtаJ.Дарtе:r в .!taчест.ве параметра.
994 Часть IV. Программирование с помощью библиотек .NET
DataRow[ 1 С;irR'оwТс;Юр(jа t е =
d,s CarI ov,eJ'1 tOI''j .1abl.e,s ["Iп:vеоtоrу" J . Sele.c::t (
string, Fcrmat (nCarID = • {О) , " ,~aTToUpGiQt€) ) ;
carRo,wTo1)pc;J;i;\te [О] [" l?e,t .}Jame" ] =' n-еw!1е'tNаmе;
dAdpater . UpdEl·t.e ('ds-СаrI nven:bory. T:able.s [" Inv<'Jri't.ory"·'] ) ;
striпg эql =
strlhg.F'orm-аt ("Delet-e Етот lдvsпtоrу where CarID = '{O"j' ,:.',
ci'irTGDelete);
SqlCornmand cmd = n.ew Sq1Cbmt1'1apd (.sql r CfI'Obj);
dAQpat~r.DeleteCommaТJd = ernd;
uataRow (J ca:rRowToDelete =
dэСа:r IrJ.veritt>ry .1ables [,"'Inven tory" ] . Sel.ect('st,rlng. Fш:mаt (
"Cё.rrID =' i(Q),1.t/ carToDelet:e»),
С& iLН,оwТзD еl et.e [О] . Delete О ;
dAdpa ter • tJpdaXe- (dsCarI mre.fltQry. Tables [ "lлvеrJt0rу 11) ) :
Здесь возникает вопрос о том. как построитель команд может строить указан
ные объекты SQL-кОМанд "на лету". Оказывается, все дело в метаданных. В среде
выполнения, когда вы вызываете метод Upda te () адаптера данных, соответствую
щий построитель команд читает данные структуры ба:зы данных для автоматиче
ского генерирования объектов соответствующих команд вставки, удаления и об
новления данных.
. __ ~, _ """..__... . о
_.~ - "_ .
2
----- ------tz·- ---.
'4 1
J
J\oНCTPYКTOP формы Вl>lПОJПИiет основную работу по СDЗданию чле.цОЗ-DеремеlI
ны:х ДЛЯ данных и зar:!олнеJ-lliЮ
DataSet. Обратите Ta1GКe внймЗние.на ВЫ,ЗОВ при
ваТ1jОЙ вспомогательной. функции B<J i 1 dTab lеRe:Lat. iо:пshiр ( ) .
publ i с Mai'hf·orm ( )
I
1 oi t ia l i zесоmРQле!.lt О ;
11 Создание ~an!l.'8pos.
ir1'\1'J'aibleAdapt er = пе'"
Sql DataAdapt.er ('''Select .. frош Iлvепtоrу", сп);
custTilbleAdёi:p t er =-n'ew
~.qlDаtаАdарtЕ:!: ("Belect " froIJ( C1!J' S1:~meIS", сп);
оГclеr-sТаblеА'dарtе'l = ре""
sqlDataAd,ap1':er (".Ss1ec:t * f rorn O:rdEors". сп);
1/ А.в'1'orенерироваИlllе Jl:онаИА.
sqlСВ1!Нl€лt о rу = new зчН:::оmmаПdВ·.Jil(lеr (inyTfJ;ЪleAdapter} I
sqlсвоrdеr з = new SqlC9 lPJnar.dBuildel' (oJ:de-х s1'аыlАdарtеrj;;
$чlСВСI:LSJ:оmегs = new SqlC'o!!uriC;!,n'dВuilder (ctJstTaGleAdapte.t).;
Затем Rbl JЮРfЦЮДИТ~ !iJT таёlлицы: Customers к таблице Order.s, Щ:Л0Лb;ly8 отНоше
liИеСustоrn~rОп:1еL. ОБР;;J:m:те внимание на то, Ч'I'D Метод DataRow_Ge1:;ChildRow.s О
!103вOJ1Яет D~JJУЧИ'1'Ь дщ;тyu R СТРОl!ЭМ дочернеЙ .аблХ'щы. ПОСi1Те этого ВЫ :можете
nPОЧ~lТатъ информацию из этой Табmщы.
3aк_~1
НOI!eP
марк.,
"""138'
eot
I
Цвет : I)blJl<!1it
~: Rusty 6U<Qer
ок
Чтобы понять, что делает эта строка программНОI'о кода, мы должны сначала
выяснить роль строго ТШIИзованных объектов DataSet.
<5d'dJ> • u '"
"" ~ w~"biAci:eu
'tJ са Prajed Rl!feo_e.
Э·~· ;С7:.
~ <~ CwSDa~t.~t4т.ыe
~ ~ CII"JOII~t.~VCI:!IQrr'l!ow
~,' ~ Qll'lDat.Sebln;..entor~~~\re!Ot
rliI .' c.rf[l.r.as.~lnv~Ior~IIE.tn!l'lll1(t..
liiI · ~ ..'
~~ ~Im
t,;; О WIlW«'''ed»Iit~,CМJt)Jl~tl'ТeЫeAc.oter.
,., lt Wj~~,~
-.,.: . "'~~"'=-~' ~~. ·_;.:'-"·... "'~:r.""::.. ~. :~ :--";::",,;..';. . :,1: ~, • ..
~ C.vlOllt8$e!O ,р(;
ISI C"_ _ Ia$et(s~~е . sen.Jil.JIoo' . SerIIIldoo'l!r\fo. $~\UI _.
·... 0-0
\ ~, G.~6~".ыeO.
.., Getт\'ре~Se~vttoem"xmI,sa-;)С:I\ISohlm!lSe.l)
[; )~- -
за ..... ч.Ни •. Бfll1l!wе 06 об"'ЬеI('fНОЙ МОАел~ ADO.NEr. з T8~ О соотвеТСТSУI9ЩИ~ мастерах Visual'
Studio 20051:abl y~a~Je ИЗ I<I1!1rJ.1 Сахила Малик~. Microsoft АОО. NБ7' 2. О для nрофесGионалов
(l'1ер. с QI>IГЛ, ид "в\'1лыi1&'\\ 2006 г,}.
J
1006 Часть IV. Программирование с помОЩью библиотек .NET
т
Резюме
ADO.NET является новой технологией доступа к данным, специально разра
ботанной с учетом несвязных многоуровневых приложениЙ. Пространство имен
System.Data содержит большинство базовых типов, которые могут потребоваться
для программного взаимодействия со строками, столбцами. таблицами и представ
лениями. при изучении материала главы вы могли убедиться в том, что в составе
дистрибутива .NEТ предлагается множество поставщиков данных. позволяющих
использовать как связный. так и несвязный уровни ADO.NEr.
Используя объекты соединения, объекты команд и объекты чтения данных
связного уровня, БЫ можете выбирать, обновлять, вставлять и удалять записи.
Объекты команд поддерживают внутреннюю коллекцию параметров, которую
можно использовать для повышения типовой безопасности SQL-запросов и кото
рая оказьmается очень полезной при запуске хранимых проце.цур.
Основным объектом несвязного уровня является DataSet. Этот тип являет
Ся размещенным в памяти "представителем" любого числа таблиц и любого чис
ла их необязательных взаимосвязей, ограничений и условий. "Красота" создания
отношений на базе локальных таблиц заключается в том, что вы получаете воз
можность программно исследовать ИХ, Отключившись от удаленного хранилища
данных .
I этой части..-,
Гл,ава 23. Web-еrраницы и Web-элементы упра!3ленияASР.NЕТ 2.0
Глава 24. Web-прило-жения ASP.NET 2.0
Глава 25. Web--с'ервисы XML
1
i
ГЛАВА 23
Web-страницы
и web-элементыI
управления ASP.NEТ 2.0
РоnьНПР
Wr!Ъ-ЦРЦil0жеНИl'J Qче5Ь сМьно оТЛRЧ8ЮТСЯ от традиц~оfP'JЫХ лриложений для
~асто.щ~rIЫX СJЩтем. Первым очевидюам О'Iщtчцем является то. -.пф .цюбое реалрнОе
Web-ЦpIOIожeцJtе преД!fола:гse-r IIспользоваяи-е, ~aK минимум:. двух соед~неfщы,х в
сеть,},jJEI.ПJИR (ИOlJеЧ}-IO, при разработке n,риложения ВПCIЛне возможно, ч.тобы рс;mи
нлиецта и c~pBepa ДТ'рr;ще. ОДf1а маш~на), 3Щ1ейст:воваННЬЦ1 машины должиысог.'1а
совать ИРnOlЛ>Зовrom-е оnpеделсщнoro Сет.евого протокола ддн усдешного осущест
ВЛ~НЩI i:YrrJ:равщ.J и приема д~. Сетевым дротокмом, соед~нщощим номлъю
TIW~ .в рассматриваемом J'IВМИ ещучsе. ЯВЛЯ~СЯ щрото.кОд НТГР (Hypertext Transfer
Protocol- протокол передачи гищрте:кста).
Когда М8ШИFlQ-1tлиентзаПУС1iает Web---браузер ITaнo~. как Net$cape Navigator,
:М-оzШа F1~.fщ или MicrGsoft Irltemet EJj:pIQrer), rенерируетса}--f'I1"P-зsnрое до.отупа
Ц кшшрt!тиом:у ресурсу (ИiЩри.м:ер, к файлу ",аsрх или *.htm) Ка удален~ой ма
шпнс-се,рвере. ПрQтОRОЛ НПР- это текстовый IJРОТОТiОЛ, построеННЫЙ на стаН
дартноЙ l1sр<щи:гме запросов и ответов. Нацример. ;при обращеl-JИЩ Rh t tp:./ /www •
Iпtе-rtес:hТr~iпifjg, COJ'1"l дрограммное обеср-€чение браузера использует WeЬ~T.eX-
1010 Часть У. Web-приложения и Web-сервисы XML
нологию, называемую сервисом DNS (Domain Name ServJce - служба имен доме
нов), которая позволяет npевратить зарегистрированный адрес URL в 4-байтовое
(32-разрядное) числовое значение (назьmаемое lP-адресом). После этого браузер от
крывает сокет (обычно через порт с номером 80) и посьmает НТТР-запрос страни
це, используемой Web-уэлом bttp:/ /www.IпtеrtесhТrаiпiпg.соmпоумолчанию.
Осуществляющий хостинг Web-сервер получает поступающий НТГР-запрос,
и указанный в запросе ресурс может содержать программную логику, способную
про читать значения, введенные клиентом (например. в окне текстового блока).
чтобы сформировать НТГР-ответ. Разработчин: Web-программы может использо
вать шобые технологии (CGI, ASP, ASP.NEТ, сервлетыJаvа и т.д.), чтобы динами
чески генерировать содержимое Н1ТР-ответа. Затем браузер клиента отображает
НТМL-код. полученный от Web-сервера. На рис. 23.1 показана общая схема цикла
запросов-ответов НТГР.
Web-cep8ep
брауэер клиента Входящий
НТТР-запрос Web-приложение
Визуализация
HTML-коАа, полученного Исходящий (любые ресурсы сервера,
из НТТР-ответа НТТР-ответ файлы
',aspx, *,asp и ',htm)
Web-приложения и Web-серsерbI
Под Web-nрuложеНllем можно понимать коллекцию файлов (".htm, "'.азр,
*. азрх, файлы изображений и т,д,) и связанных компонентов (например, таких как
библиоте1Са программно,о кода .NEТ), хранимых в отдельном семействе каталогов
на данном WelJ-сервере. Как будет показано в главе 24, WеЬ·приложения имеют
специфический ЦИЮl существования и поддерживают множество специальных со
бытий (например, события начальной загрузки и окончательного завершения ра
боты), н:оторые вы можете обработать.
1I
,
Windows ХР Ноше Ed.itiot1 rlO.rr.дeРЖЕУ 11S '}Je пр~arает вообще} . Пuэтому. в Зави
симости Ьт конфиrурации еашdJ мцшин:ы разработки, вам. ВQ3Можно. придется
установить 118 вручную, для этого откройте O1Ц;IP Установка 1>1 удаление программ
(Add/RemO\!e Рщgram). из пащш Панель у.правления (~Jitr:o] Рапеl) и выf:I.ерите в нем
Уст,ановк-а КОМПОFlентов Windows (1\dd/R:emove Wiпdоw_s C6mponents},
ЗамеЧ8име. Сервер 115 лучшеустаl:Ю5J.1ТЬ до УСТЦt1Овки .NEТ FГarnework. ~J1И yOTaHoвmъ 118 после
У{;Т~НОВJЩ . NEТ
'Framework, тО Web-арWlО~6I!ИЯ АЭР.NЕТ не будУТ выполняться J(oppeJqJ,tQ (B~
увидите тОлько пу~тые cтpaH~Цb') . 1( счастью. можно настроить 11$ на щrддержку .NП-припоже-
ниiit с ПОМОЩЬЮ заПуQk<!!. УТИЛИТЫ KOMaJ-IДI:fОЙ строки .as:p net regi i$_ еХе {о флагом /i~.
"f "... .•
~IFЖГх ~ ~ ~ [f .~
WebDev.WehS e r ver.ex ~ - ?
WebDew . We:bServer , ехе / por·t: 12] 4 5 /path: " С : \ С о dеТ еSLэ\Са :r s We,bS i t e ""
Во многих цримерах Из ЭТОЙ:$i сдедУЮЩ~Й rnзв, We1DDev .We b8e:rv,er . ехе будет ис
ПОЛЪЭ(!lВа:гься через Vlsual Studl0 2005. 'Сде.щует учитыватъ то, что этот Web-серве~
не предна.эна"Iен дЛfl ХОСтИЮ-8 Web-пр'ИложеI-ll!l.й; проиющдственно'Го уровня. Он
npедна.'ша'lен иcw.tЮЧИТедьно ДЩ:I целей разработки и тестирования .
Замечание. Пр~.ект МЬпо (см. тл~ву 1) f1редлагает беопnатное расШ\llр~ние ASP.NCГ ДЛ!'! Web-cep-
вера Apaohe. За б0лее ПDдроБНой }1НфОРМElцией обратитесь по адресу:
h ttp,_: ! /www·. ffi9л о-рr оj'е.сt , СQJП /АSР'. NE.T
Роль HTML
Сконфигурировав I<атЩJОГ длп ~Boeгo Web--ыриложеНин. вы ДОЛЖНЫ создать и
его содержимое. Напомним, что WеЬmРШtDженue-
' это просто теРМШI, ИСII()ЛЬЗУ
емый для o{iознач~ния множества фаj{лов, обеспечиваю'-ЦИХ фуmщионировайие
узпа. ЭнаЧИ'I'eJJЬнав часть этщ файлов будет tюдержать €инта1tсические леl~Семы.
оцредел:еgные lJ рамкщс HТМL (RyPertext Markup Language - языiranертекстово.й
раз:метI<И) . ffI"МL - это етандартць!й fI3blR, используемый ДЛЯ описания того. lUU<
.в ОЮiе браузера юrи~та долж,:,щ В;ЬШОЛНЯТЬСfI визуалиаация БУI<Валъного текста.
изображений. вне1IПЩX С(.':blЛОК ~ р~ли"lных элементОВ графического интерфейса,
Этот специaJ1ЬИЫЙ аСПеКТ WеЪ--рззрабо:I'Ю:I ЯВШieТСЯ ОД1l0Й из главных UрИЧИн
столь распространенной }fеJJюбви ПрОГраъ!МИСтов . }(Q1'ОРУЮ они испытывают Е
раэраБОТI<е Web-протрамм. и ~ОТИ cOBpeмeннЪie средства Web-разр.аБОТЮI {ВКЛlО-
j
1014 Часть V. Web-приложения и WеЬ-сервисы XML
чая Visual Studio 2005) и платформы (такие как ASP.NEГ) генерируют большинство
НТМlrкода автоматически, сегодня для успешной работы с ASP.NEТ все еще ВЮЩIО
хорото понимать этот язык. Данный раздел, конечно же. ни в коей мере ие пре
тендует на охват всех аспектов НТМL, но давайте рассмотрим основные.
Структура HTML-Аокумента
Файл НТМL состоит из множества дескрипторов, описывающих представление
данной Web-страницы. l{aн и следует ожидать, базовая структура любого HТМL-дo
кумента примерно одинакова. Например, файлы *. htm (ИJПl, альтернативно, файлы
*.htшl) открываются и закрываются дескрипторами <html> и </html>. обычно в
них определяется раздел <body> и т.д. Следует иметь в виду. что HmL не чувстви
телен к реtистру символов. Позтому для браузера <HTML>, <html> и <1-Itшl> оказы
ваются идентичными.
<html>
<body>
</body>
</html>
Дескрипторы <html> и </htшl> используются для обозначения начала и конца
документа. Как вы можете догадаться, Web-браузер использует эти дескрипторы.
чтобы выяснить, с какого места следует начать и где следует ЗЮiOнчить обработку
при знаков форматирования. указанных в rnавной части документа. Почти все со
держимое документа определяется в paMI<ax дескриптора <body>. Чтобы немното
"ОЖИВИТЬ" страницу, определите ее заголовок так. как показано ниже.
<html>
<head>
<title>Web-страиица Cars</title>
</head>
<body>
</bady>
</html>
Вы. наверное, догадались, что дескрипторы <title> ИСПОЛЬЗУЮТСЯ для обозна
чения текстовой строки, RОТОРая при вызове этой страницы должна размещаться
в строке заголовка окна WеЬ-браузера.
Разработка НТМL-формы
Реальное действие в файле * .htш происходит в рамках злементов <fоrш>. IП'МL
формn- это просто именованная грутша связанных элементов пользовательского ин
терфейса, используемых для сбора данных пользовательского ввода, которые затем
передаются Web-приложению по протоколу H~ Не следует путать НТМL-форму со
всей областью окна браузера. Фактически НТМL-форма представляет собой логиче
ское объединение элементов, размещенных между дескрипторами <form> и </fоrш>.
1
i
ДЛЯ id и пате этой ФОРМЪt указано 3Н8чение defaultPage. Raк правило. от
крывающий деСКJЛillТОр <form> задает также атрибут acti оп. указывающий адрес
URL. по которому сд.е.цуе'f передать данные формы, и метод переда qц этих да.нных
{POST или GET). Эrr-й ВО3МQЖН.ости дескриптора <.fo!'m> мы рассмотрим чуть позже .
ПQка что давайте БЫЯСЛИМ.RaIO:(е элементы могут раамещ,аn,сщ Б НТЩ-форме.
в панели инструмент'ОВ Visual Studio 2005 предлагается специальный раздел HTML.
в катаром сrpyпnированы tвя:.;Шнные с НТМL эдемеllты управлеlffiЯ (рис. 23.4).
ltjj~"И~~~:::1"~
о IrP.t, (~) '~
~ ]фJt (А-) ~
c ..
~ Jф.i:(SobQt.j "~
~ inI!<t (T~)
~Щ!Ut (~J
~ Jt,put (Pмswor<1)
o 1npur (Q1ecl!tioxJ
Ф lnput(Roc8o)
~ ,i; 1npш (1'~)
;~f::~~.~~~;-- - ~
Рис . 23.4. Раздел I-IТML в окне панеflи инструмеюоs
<ьt.шl:>
<h .e'ad>
<1.1 tJ e >Web -С'l"рающз\": аr~<1 t i tle>
< / Ь,е-а.d>
J
1016 Часть V. Web-приложеfiИR и Web-сервисы XML
-
P,op"rl,t'S
.- -- - ~- . -
8ackgr'ound
~a"ajoWhite !d
8gPropertie$
BottomМ"'gin
Chor$et
'.-
о
a...._---
s.
'. _~ ,_.-
_ _ ....,. ,. _ ,,_ ._-
.,. _
lIQCoIor
Document bod<q"'Jnd сo!or.
~ i:' _
- _._- - - - - ~- __ О!
ИМЯ ДС ЛFЗQВII:rеля: ,
-~.
г IЭmр;;D~Т;' j 1 РБРDt: j
Рис.2;3.6 , ,ИСJ<ОДНЫЙ вид страницы, оtщраненfI'ОЙ 'в фаиле 'd efa u 1 t.. h'tI!1
Роль сценар,иевкл,иента
Дroщый файл ~. )-Y't !111\южет содер~\'юъ блон кода сцtЩаJ;>}{J'!, Щ1ТОРЫЙ буд~т ПDме·
Щ~JJ !=I ответный j10TOj't и обра:ботШ1 брауверам, запРQС~ШИМ ЭТОТ ПОТОК" Есть две
'гдавные ПРИТfИНЫ. ~10 IЮТОРЫ)I.J I:Iсаолъзуются <.'цеН~'Р1Jj:I ~eН'l'a.
3амечаниа. ASP. NEТ поддерживает свойство HttpReques t.8ro ws e r, которое позволяет в сре
де выполнения определить возможностИ браузера, отправившего текущий запрос.
3амечаниа. Чтобы еще больше усложнить ситуацию, напомним также о JScript . NEТ - упраll11яе
мом языке программирования, с помощью которого , используя подобный сценариям синтак
сис , можно строить компоновочные блоки .NEТ.
ские". так и .NET) и Т.д. Для нашего примера мы используем "массический" файл
ASP с именем Cla s sicAsp Pa g e.asp. Обновите свой файл default.htm. указав в нем
следующие атрибуты в открывающем дескрипторе <fo rm>.
<fo r m n arne= "de fa \Jl t.Page " i d=" d efaul t Page"
асtiоп="httр://lосаlhоst/Саrs/СlаssiсАзрРаqе . asp" method = "GET" >
</ form>
Добавленные атрибуты гарантируют, что при щелчке на Rнопке Отправить
данные формы будут отправлены файлу Cla s sic Asp Page,asp с указанным URL.
Указание metho d = " GET" для режима передачи означает. что данные формы при
соединяются к строке запроса в виде набора пар имен и значений. разделенных
символами амперсанда.
<%
Dim pw;:\
pwd = Request. QueryString '! "-:Х:t:.FEl55WОГО")
'Rеs-роnэе, W~ i te( pw.d I
%>
ОЧевидно, чого !iJ0ъеКТЫ Т1.8 q 1.) est И RеSF(УПЗ~ f\:.ТЩС;СИl:-1еС.НОЙ схемы А$Р' предла
гают цeJIЬ1Й рщ ДОДОЛНИТf"ДЪ8ЫХ членов, :кроме показанных ВblIП€. Jt т()щ ще. ц
раМЩIl!: ЩIассического ПОДХ9,ца ASP оцреДe.JЩетсн Ilебольшой набор доuолнитеJJЪ
НЫiК COM--'Оt1ъе:rпов(SoeвSiОn. $~rv€:r-. Appli<:;ctti::'1o 11 т.д.), ЩIторые вы ~ можеТе
исI10ЛЬ31JRa1Ъ при ЛQстроении Web-ПjJl'1Ложенин.
3аме't81tИе.S ASP. NET эти COM-QбъеКТbj оф ..ЩИarJЬНt) н'е оуществуют. Однако вы1 увидите., 'Iт05азо
вый класс 5'у в\:ет. WE'ot, ,1.1 1 .Р'аяе ОПfJе.целяе;r С80Й€;Тва с иденl'ИЧНЫМИ именами, ВЬ:fвраЩ8Ю
щие оБЬf}ктhl (]ilнадОГИЧгIЫМИ ВОЗМОЖНОСТЯМИ,
<.body>
<Ы аlig п= "сепtег">Вот что вы нам прислали:< / h1 > < Р аligп="сепt е r">
< Ь>Имя пользо вате ля: </Ь>
<i1; = Request. Form ("txtUs erN ame") %> <br>
<Ь >Пароль: <!Ь >
<%= Request. Form( " txtPassword") %> <br>
</ body>
На этом наше обсуждение основ Web-разработки завершено. Надеюсь, что даже
если вы до сих пор не имели НИI<акого опыта разработки Web-приложениЙ. теперь
ВЫ понимаете основные принципы создания таких приложенИЙ. Перед выяснением
того, как шrатформа .NEТ совершенствует существую!ЦИе на сегодня подходы, давай
те потратим немного времени. чтобы Uпокритиковать" классический подход ЛSР.
Исходный КОД, Файл примера ClassicAspPage размещен в подкаталоге, соответствующем главе 23.
• Web-формы и Н1МL-элементы
• Web-сервисы XМL
II Прощрвнст_а "~H
S уst ЮТ1 , W;e:b-. li' зm filе Определяет tИ-nЫ , исr:юльзуемы'' ДJlЯ работы с гтЬльзова
тепьсl<~I\4И профилями АБР. NIIJ
sy,s:t е,!'1 , W!i= Ь . 1) 1 ОпредеI1ЯЮТ ряд 'ТипоВ ' лозвqляющих СОЗДЩЩТЬ ДЛЯ Web·
S;y ste.m,W\!:.tJ . Ul. W~b(: (mtrol s прилС)же-ний ПJ)ОГраммы клиеmа с графичес~и.., паЛЬ3ОВ.а ·
Эуs tеrп.wеЬ . (Г[ . Е t w. lCDп,tгоlз Т€il I>СКИМ интерФ·еWг.ом
Подход, принятый в Visual Studio 2005 по умолчанию (при создаиии нового про
екта Web-узла), использует так называемую технологию вн.ешн.его кода nоддерж
/си (code-behind), предполагающую отделение программного кода от НТМL-логики
представления и размещение их в двух разных файлах. Эта модель исключительно
хорошо работает в тех случаях, !шгда ваши страницы содержат большие объемы
программного !{Ода или в процессе разработки Web-узла принимают участие много
разработчиков. Модель. основанная на использовании внешнего кода поддержки,
имеет несколько преИмYIIIеств.
- - .,l~i
,"'-- '..G-1.....
Рeiforп!ancе
S Web
\II5цi1I~,шr
с#
VJi
ViStJaI ('но
5cфI;
Эамеча"lU!. В оrnичие отболев РilНliИI{ версий VisuaJ Studlo', вид Source в 'Visual' StudJo 2005 nplaA~
ilагает П()ЛНОЦ~ННУЮ ПО):I,D.ержку IntelllSense и позволяет перетаскивание злемеюов пользова
тельского интерфffi1са непосредстве~о в окно IrITML-', Кi'Jда.
В.панели' шrGipyмemOB (О1СНО Toolbox) Vi'Su:al Studio 2005 ОТi'{ройте раздел Standatd
и nepетащитеэлеМe:I-trы yпpaв;Iешrя Butt bQ, La'b el и 'Grid.Vie w' в ЬщJO Npоектиро:ва
НИIl r:тpэницы (элемент ,GridlJ:Lew :можно найти в .разделе Dзtа окна TOOlbOx). Не пре
небреI"aЙТе использованием ОЮlа свойств (или JпtеШSеl1sе дщJ НТМL) при устанОВ
ке рэзлиЧНI:iIX СВОЙСТВ элемеl-!ТОВ :и:wrерфейса и укажите ддя 'Каждого Web-элемента
ПQдХод.нщее имя с помощью свойетва I D. На рис. 23.9 ПOlf"щан QДИН из в:оэм:ожных
вариантов ОфОРМl"lенn проекта (сдержашюетъ здесь ЦРШIВллетСn npeДEaмepeHHD,
чтобы минимизировэть объем генериру~моro кода рэзме';ГКИ) .
. ",.'
... "'" I'
J
1028 Часть V. Web-приложения и Web-сервисы XML
Кроме того, в вaпr блок <script> добавляется обработчик события Click сер
вера (здесь обратите внимание на то, что входные параметры в точности соответ
ствуют требованиям целевого делerата system.EventHandler).
<script runat="server">
protected void btnFillData_Click(object sender, EventArgs е)
{
)
</script>
Реализуйте серверную часть обработчика событий так, чтобы использовался
объект чтения данных ADO.NEТ дЛЯ заполнения GridView. Также добавьте дирек
тиву импорта (подробнее об этом чуть позже), которая уЕажет. что вы используете
пространство именSystem. Da ta, SqlCl ient. Вот остальная часть соответствующей
программной логики страницы файла Default.aspx.
</s·cr.1pt>
<htJrll xmlns= "b'ttp: J ,'w,Ww. W3. org/ 1999 (xr,tmJ, 11 >
</html:>
WEbclev. w,ebs~rver" ы<:е I port:: 1 23<4 ') !pa·t b; "С: \Code TEst-s \8 ing l,r?Pa.ge'Мooel;;
l'etNams
Совсем просто. не правда ли? Но. как говорится, все зависит от мелочей, так
что давайте рассмотрим немного подробнее композицию файла *.aspx.
Директива <%@Page%>
Прежде всего следует отметить то. что файл *.азрх обычно открывается набо
ром директив. ДИрективы ASP.NEТ всегда обозначаются маркерами: < %@ ХХХ %> и
могут сопровождаться различными атрибутами. информирующими среду выпол
нения ASP.NEТ о том. как обрабатывать соответствующие данные.
Каждый файл *.aspx должен иметь, как минимум. директиву <%@Page%>. ко
торая используется для определения управляемого языка. применяемого в рамках
Атрибут Описание
Директива <%@Import%>
в дополнение к директиве <%@Р а g е %> файл *. а 5 I? х может использовать раз
личные директивы <%@Import %> . чтобы явно указать пространства имен. необхо
димые для текущей страницы. В нашем примере указано использование типов из
пространства имен System.Data.SqlClient. Ясно. что при необходимости исполь
зования дополнительных пространств имен .NEТ нужно просто указать несколько
директив <%@Irnport%>.
Замечание. Директива <%@Import %> не является необходимой, если применяется модель стра
ницы с внешним кодом поддержки . При использовании файла с внешним кодом ПОДlJ,ержки для
указания внешних пространств имен применяется ключевое слово using С#.
• Syst;:;;m
• Sу s tеm.СОllес:ti.олз
• System.Coll~cti.Qns.GeoeriC
• Sу.st;еm. С опfigurзtiоп
• &ystem,. iO
• System.Text
• S'Y'steтn .Text. RеgulаrЕхр:rеsэiоrL$
• Все прoecrpанс.'ТВа имен, С8Язанn.ые с syst-еJ)1.Wе,Ь
Блок <script)
в соответствии с моделью ОДНО);[ОДУ лъной страницы файл YI. а spx MQ}fteT со
держать логшtY сценария серв.ериоЙ СТQРОПЫ. ЕОТ~)РъiЙ должен выполняться на
Wеь-сервере. Блони программного коДа. оцределеШlblе для сервера, должны въl
llO:пняться на сервере. позто1V!у ДJ1Я.них nСПОЛЬЗуеТСЯ атрибут r·Lшаt="sе.r,'~r".
Ее:ли: атрибут :tunat=" s~.cv.er" не yщtзан.. среда ~ьшолвенин предпо.l1'aГаe"I: что со-
y~ ~
QТ.ветствующии l1ЛОR ,flВЛЛt!тся сценаРИ€l\ot K.;'!uel-lmq. RОТopblИ следует отправить с
~сходmцим. Г.JТrP-Oтвe:rOM.
ДеклараЦИll311емента ASP.NET
Последним из рассматрйВаeмъrx З~(~Ь щшросов цвляется структура определе
НИЯ17лементов управления Bu t Lon . l.a b€l и G:'J;" idView Web-формы. Подобно ЛSР и
JПМJ." Wеь-элемеmы ASP.NEJ размещаются в ьюнтеКС'1'е <fоrш>. Но н этом случае
ОТIqJЫJШЮЩИЙ дес&риrrrор <f и~m> соupовождае~аТРJoJбугом r u п а t="зеtlтеr". Это
оче.lД, важно. песю')лЫ'.:у тем caMbIМ деекриТJТClР И'liформпрует (феду:вьmолненЮf
MP.NEТ о том, что перед размеще.l;tи.е:м НТМL~Rода в потоке ответа соатветствую-
1032 Часть V. Web-приложения и Web-сервисы XML
</form>
Исходный код. Файл при мера SiпglеРаgеМоdеl размещен в подкаталоге, соответствующем главе 23.
!
1_ I'1:и ",,!,pl,,t.,.
I .;}]
11 S....ch Onlin.
Templ.t", .. ,
ОК JI C_ncel
На рис 23.11 обратите внимание на то, что вы можете сразу указать место рас
положения нового узла. При выборе File System ваши файлы будут размещены в
пределах одного локального каталога, и страницы будут обслуживаться с помощью
WebDev .WebServer.exe. Если выбрать FTP или НТТР, узел будет обслуживаться в
рамках виртуального каталога, поддерживаемого IIS. Для нашего примера нет ни
какой разницы, какую из возможностей вы выберете, но для просто'Гы давайте вы
берем File System.
..
3аМjlчаНllе. ПР\II соэдаН\II\II WеЬ-узла ASP..NE'Т .8 Visual Studio .2005 соотаетcrвующий файл решения
(".з10) 1"10 УМОЛ'-iанию P<i'змщцае.,.о~ в лапке МС'И дGкумен'l!ыv1з uаll studio. 2005\
Proj ec·ts, Файл'ы содержимого узла (такие !С_Ж, например, ". а spz::) будrr Н8ХQАиТЬСЯ В ука
занном ЛО.КnЛЬ/-IOМ j(aTiW1or~ или (при I4СПОJ1Ь3GВaнV!И 115) в физ~чеCl.(ОМ фаЙ'ле •. отображающем
ея в .виртуалi;IтIЫЙ каталог,
;-~
. .1-."
5nhJon
-
~I~,;r
.... .
.17;т-- &Pber/~ d~_
__ , - - ___
О _ _ '- .~ ._ . _
J
Рис. 23.12. Файл с ВI~е.шним I(QoЦoM nоддер)((1о:И, аСС/:ЩИlrlрованный с файлом '*. азрх
Если при создании проекта вы выбрали вариант File System, то при вьшолне
нии Web-приложения автоматически cTapryeT WebDev. WebServer. ехе (очевидно,
что при выборе IIS этого не будет). В любом случае используемый по умолчанию
браузер должен отобразить содержимое страницы.
Но. чтобы выполнять отладку Web-приложения ASP. NEТ. ваш узел должен содер
жать правильно скомпонованный файл web.config. В главе 24 структура файлов
Web.config рассматривается подробнее. но. по существу. эти XМL-файлы служат
той же цели. что и файл app.config выполняемого компоновочного блока. Если
ваш проект еще не содержит файла Web.config, Visua1 Studlo 2005 это обнару
жит и добавит такой файл в ваш проект. Соответствующим элементом является
< compi 1а t ion>.
< сопfig\паtiоп
xmlns=''http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.web>
<compilation debug="true"l>
</sys tem.web >
</configuration>
Вы также можете разрешить поддержку трассировки для файла *. а spx, устано
вив для атрибута Trace значение true (истина) в рамках директивы <%@Page %>.
1
rrl8sa. 23. Web-с;траНk1ЦЫ и Web-элементы управления АSР,NП 2.0 1035
<%@ Pag€ Langu:age="C#" AutQEventWireup="true H
CodeFi le="D€faul t • aspx, C~" Inhe'T i 't.$=''''_ Oefaul t" Tra.ce=" true" !1,> ;>.
Подкаталог Описание
App_Browsers Папка ДЛЯ файлов определений. которые ИСПОЛЬЗУЮТСЯ для иденти
фикации браузеров и выявления их возможностей
Арр Code Папка ДЛЯ исходного кода компонентов Или классов, которые вы
хотите компилировать, как часть вашего приложения. Программный
код из этого подкаталога компилируется при запросе страниц и ав
<compilation debug="false">
<assemblies>
<add assembly="SysteJD_Drawing, Version=2.0.0.0,
Culture=neutral, рuыlскеутоkеn=возF5F7Fl1D50АзА''/>>
</аssешы1еs>>
</compilation>
<authentication mode="Windows"/>
</system.web>
</configuration>
Как видите. каждый компоновочный блок описывается с помощью той
же информацию. которая требуется для динамической загрузки через метод
A.ssembly.Load (} (см. главу 12).
ния файлов с управляемым программным кодом разного типа (*.сз. *.vb и т.д.).
Для примера предположим. что вы добавили в корневой каталог приложе
ния Web-узла папку Арр Code, содержащую две подпапки (MyCSharpCode и
MyVbNetCode). которые содержат фaйлъr. написанные на соответствующих языках.
После этого вы можете создать файл Web.config. который указывает на эти под
папки с помощью элемента <codeSubDirectories>.
<?хml version="l.O"?>
<configuration xm.1ns=''http://schemas.microsoft.com/ .NetConfiguration/v2.0">
<appSettings/>
<c onnectionStrings/>
<system.web>
<compilation debug="false">
<assemblies >
<add assembly="Sys tem .Drawing, Version=2.0.0.0,
Culture=neutra1, РubliскеуТоkеп=ВО3F5F 7 F11D50АЗА" />
</assemblies>
<codeSUЬDirectories>
<add directoryName="МyCsharpCode" />
<add directoryN~"МyVbNetCode" 1>
•
Замечание. ПаПJ(д Арр _ Code \.iaCTO используется и для хранеНИQ файлов , которые не ЯРflЯIQТСЯ
ф~ла~и Q лроrpамМНЫМ кодом на конкретмом ЯЗЫIЩ но тоже оказывщотся необ)(OДIoIМЫМИ (на
пример, файлы *.xsd. -;.wsdl и Т.д.) .
Аатоматически Сiеl4ер~рованныЙ
RОМnОНОВQЧ'flЫЙ блок в a'&p n et_ Ер.ЕХ!?
,
"
КОМhИnЯТОР
System.Web.U'I •.Page среды J:I1>mолнеНИfl
(базовЫй xnасс ДЛII !lC6X
кnaccoв *_IiSrж)
,...':"-: -
,
MyPage_a:8PJl "
" - M:yP.a ge .aspJC.
,
(Aмнat.l1N8CКМ oll~1i И '. <htm.l>
IfOМП~'rМП Юlщ:са)
.. .
<j htm1 >
- - 1"
,
I<омпиnятор
среды System.Web.OI.page
IIЫПОЛ11QНИя' (ВаэОSl,iйlФасс,для всех
КЛассов ._aзpJ()
",
~"
••
ДВтомэтичееж,и сгенерированный ••,
комлоi'j08очl'lый блок .м~,Р.аче .аsрк
в' aspnet _sp . e')le <ht m.l>
...
Myi'age ...:i'iзрх. </html)
(готозыlй кnaco)
ЗIIМ~Ч8ние. 8 ASP,NEТ 2,0 тепвр'ь Щ)*~IO выполнить преДj(ОМПИЛЯЦИID всех (или He~OTOpoгo ПОД
Мtlожествз)' страниц WеЬ·уэла ';: ПОМОЩью спеЦИa.J1ЫJОГО инатрумеwта J(оманд~ой СТРО ' КИ
a.spn,et cQmpil €1 r ,ехе, Более конкреl'tot8ЯИНфОРМация по этому ВОПРОСУ имеется в дo~y
ме:нтациИ,NЕТ Framework 2,0 SDK.
Тип System.Web.UI.Page
Первым интересующим нас родительским классом является сам класс Page .
Ниже описаны его многочисленные свойства, обеспечивающие возможность вза
имодействия с различными Web-примитивамн. такими как переменные приложе
ния и сеанса, запросы и ответы НТТР, темы и т.Д. Описания некоторых их этих
свойств привоДятся В табл. 23.4.
Cli e ntTa.r get Позволяет указать способ визуализации для данной страницы в зависимо
сти от запрашивающего браузера
Theme Получает ИJ1}t устанавливает имя темы. используемой ДЛЯ текущей страницы
Описание,
l
•
Этот ПОдХод ие ТQЛЪКР соответствует строгим 1Jрmщm:xам ООN. .но при этом во·
обще .не ПРИХОД~ТСR ,забо-rитъе.в: о том , шm ~СТНШLЯЮтсg даmn.tе ,формы (GE7 или
~O ST) . К тому же J;IеПQсре.дствеffi:{3Я рабо-та с 6.ц~мeнтOM упра:вленин "Гораздо б.оль
!Де соотве1'ствуеттребовани:нм типовой безопасности, поскольку здесь возможные
ошибки ввода будут выя5лIjLы ~e да ~тanе :крМIIИJ1fJЦИИ,' а не в. среде выполнения.
Конечно, это не значит. что J\ЗМ в ASP.NEТ вообще 'НИКЩ'да не придетa.t1 иtпоJIЬЗО·
:эатъ свойства F o r ,m ~ Q,Щlr УiSt .r i ng. ~O he-оБХQДИМОCТh в йх исп.ОlIЪзовании c:ylЦe
ст.веннР уменыцится .
СвойствоlsРоstВасk
Еще одним очень важным членом }fttp Reque-st mmя.eтся своЙ'етво IsPe s t'Вa c k.
Напомним. что ·postbac~· обозначает ВТQрично~ орращение :н JЮНJ{ретffiJЙ Web-
стрaIЩце в ходе ОЩlого сеанса свдзи с сервером. С учетом ЭТО1'о долЖно быть "'nо
J-"fRТНО, что CB.oik'FRO I'S'Po stBaek возвращает true l14стинаJ. если теь'УщийНТГР
запрос oтapaв.т.teH уже зареrИСТРИРliШа.нным .Nfl.стоя:щиЙ момент пользователем. и
t alse (ложь). если это первое вза:щ.юд;ейс'твие пользователя со с.траницеЙ.
ОБЫ'ЧflО необходимость в оцредщrении тРП) , -.:rгO текущий НТТР~запрос ввляет
с.я :вторичным. ВОЗЦДIЩет тоща, ~oгдa нщroтор~ 9ЛOR npотрвммно,о шща должен
выполняться только при первом о.бращеЩiJ1: ПОЛЬ::JQватешr R странице. НапрИмер,.
J
1046 Часть У. Web-приложения и Web-сервисы XML
Свойство Описание
Conte n tTyp e Читает или устанавливает МIМЕ - тип ВЫХОДНОГО потока НПР
Sta t u s Desc ription Читает или устанавливает строку состояния НПР -ответа, возвращае
мого клиенту
Метод Оnисакие
Генерирование НТМL-содержимого
Пожалуй, саыОЙ известной сферой прйменен:иятипа RttрRе5роп.sеНБ.iIЯетс.fJ З8:
пись cuдержимото непосредствеmш в выходной t10ТfЖ Н'ТГР. Мe-:roд fjt'tpRespons~.
Write (} позволяет передать J-IТМL-дескрппторы или вообщ€ mобые строковы€! ли
Teparrы, Метод НttрRезроыsе.WritеFilе () раешир.яет эти воэможности с 'тем. ч'Iо
бы вы МО:rJIИ yRaэать имя фиаичеСRОГО файна на We'b-cepвepe. содержащего данные,
напpawmемые 11 ВЫХОДНОЙ потои (это оказывается очень удобным в том случае, ког
да требуется отпрmштъ СQдержимое уже сущеСтвующего фafтa* ..t'JСЛI).
Для прим:ера npедnолоw.им, что вы добавНiIИ в свой фaiш '*. аврх еще один тип
BU't.tOD, ROторыйреалИзует обработчик соББI'I"И".Я,СliсК сер:вератан.
Перенаправлениепользователей
Друтой возможностью типа HttpResponse является перенаправление пользова
теля по новому адресу URL.
protected void btnSomeTraining_ Cl ick(obj e c t sеп dеr, Even tArgs е)
(
Rеsропsе.Rеdirесt(Пhttр: !!www. IntertechTraining.c om") ;
Кроме события Load. тип Page может вьmолнять перехват любого из событий,
указанных в табл. 23.8 в том порядке. в котором эти события возникают.
..
Оп~оание
HТТP-OTBeT~
Unload страница и ее ,элеМеНтЫ управден~я з.аверLL!JИjJИ пjJОL\асс передв'4И даНных, и
объект страницы готов ~ yt:IloL·поженмю. Взаимодействие с ИСХОДЯЩИМ НТГР
CJТBвJOM В ,ЭТОТ момент породит ошиfiКIjI среды 8ЫПОЛ,неНИR. Можно выполнить
ЗЩ(fЩ1 этого Gобьпия ДI1я"уборки м,(сорэ" На YPOBWB страницы ('IтоБы за
крыть фаi1J:lЫИ бащ,1 дafoIt1bIX, BbI[1DflIH·m. процедуру выхода из систеМЫ, осво
бодить ресурСЫI и т.д,)
Роль атри6утаАutоЕvепtWirеUр
Чтобы обработать события дmr страницы:, нужиодобавитьв б.поЕ <sc.ript> шш
файл с внеuшим RQДОМ llодцер:lf>.'lШ rroдходв:щий обрабоТЧШt событнн. В O~ от
ASF.NEТ 1.х. тшшръ:ае требуется ВВОДИТЬ всю праграмм:ную логику соБЪiТИБ вруч
н:ую. Нужно толыto оп:реде1lИ':fь соответствующий ме:гОД, ИCIIOлъзу.в: след.У1ОЩИЙ ша
ШЮН.
Как подсказьmает имн этого атрибута, при его активизации будет создана не
обходимая оснастка событий в рамках автоматически генерируемого парциально
го класса. описанного в этой главе выше. Если установить этот атрибут равным
false. не будутвызваны обработчики событий ни для Lo ad. ни для Unload страни
цы _Default (вы можете проверить это непосредственно. установив контрольные
точки в пределах обработчиков событий Page _Load () и Page_ Unload ().
Однако, если вы используете стандартный синтаксис событий С# для обработ
ки событий Load И Unlo a d , как показано ниже:
Собьrrие Error
Еще одним собьrrueм. которое МQжет nРQИСХОДИТЪ в цmще <:уЩествовмщя: стра
FIИЦJ>I, ЯВЩIетса еобытие B:rror. 1tompoe такще работает .в паре с делегатом Вуз (е!'!1.
E,1~h.t.H<Hldler_ Это событие ВОЭЕЩRaеТ в том С.JJyЧ<lе. когда метод nPОИ;3ВОДЦОГО ОТ
page тmrn генер.ируt:Т ИСдлЮЧецие. оставmееся: без ЯЩiОЙ обработки. ПрftДnОJlОЖ:ИМ.
ч.ТО вы обработали событие Cllck для типа But tOE на странице. }<I в преДелах обра
ботчика собыТИSI: (эдесь од IIа3ывается btI1GetFile _ tlick) вы пытаетесь заIЩсать
содержимое лшщлъного файла :6 НП1'-ответ.
Та1tже преДIЩЛОЖИм.. '1ТQ вам не удалое.,. ПРQвери:ть присутствие э;rого файла
с UОМОЩЪ1Q c-r:щщартiНОЙ технологии стр)'КrypИРО:6ЗНiН()Й обработки ИСКlIюченйй,
ЕсJIИ при ЭТОМ ВЬJ предусмотрели обработку события Er ror СТРЗ!:IИЦЫ. вы поду-чи
те шзr).'С решит}> воанщсmyIO проблему. чтобы по,ПЪЗQватель не yJщдел безобРЗijЦУЮ
информацию 06 ошиБJCе. РаеСМОТРИ1'е следующий програм,мныЙ код.
J
3дееь обработчик события E.rror Н8.'ЧШIаетС.я с 01ПIСТКИ всего содержимого
имеющетося нтrP-oтвeтa и вывода общ",го сооБЩ~JI 00 OIIIИб:ке" Ч;rооы ПD.lI)"fИ'I'Ь
доступ К ROН1tpетвощ объекту ,Sуst.еш.ЕхсерtiОIJ. вы можете использовать метод
Ht:'tpServerUtili.ty.GetLastError{). доступ к Rоторомуобесuечиваетунаследо
яа:в:н:фе свойство 'Server,
v,oid Defs:Ult_Error (object seI1der, EV1entj'l.rgs е)
Rеsр<М1S<!. Cliaar () I
R:еSРQлsе, Wri te ("Извините, .. не могу най'j'·~ необходимый файл. <Ь;>" );
1052 Часть У. Web-приложения и Web-сервисы XML
J
1054 Часть У, WеЬ·пр~ложеНИR и WеЬ·сервисы XML
Свойство AutoPostBack
Следует также подчеркнуть то. что многие Web-элементы управления ASP.NEТ
поддерживают свойство AutoPostBack (это очень важно для CheckBox. RadioButton
иTextBox. а также для элементов управления. получаемых из абстрактного типа
ListControl). По умолчанию это свойство получает значение false (ложь). что
означает отключение автоматической отправки серверных событий (даже при на
личии соответствующей настройки в файле внешнего кода поддержки). Во мно
гих случаях это оказывается именно тем. что требуется. Но если вы хотите. чтобы
какой-то из элементов управления обращался к обработчику события на сервере.
нужно установить для AutoPostBack значение true (истина), Это может оказаться
полезным тогда. когда дaннъle одного элемента управления должны автоматически
!
J
1056 Часть V. Web-приложения и Web-сервисы XML
<asp:HyperLink
ID="HyperLinkl" ruпаt="sеrvеr">Гиперссылка</аsр;НуреrLiпk>
</asp: Panel>
lblControlInfo.Text t-helnfo;
»
~ L~ !~;'! floИo; ."~.). m.бражое ~)
=
J')
. l K,lo~1(o I
Г.f(n.~j;>c(;blJU(a
H~e = S~emW~Ъ.UГN~ЬС\>nl:с"Is.нуре(LirJlc
ID = ц,&.егLШk 1
V;s.iJ:,le= Tfue
• ~TJewS~afe =" Тше
..
"'A1'1''''''''''''~НТ1'ac-«Тb
"~ходныИ КОД. ФаЙilJы примера DynamicCtrls ра:змещеfjы в поw:аталоге, сратвеТСТБующем таве 23,
РохеСо10!: Читает или YCTВ:tIa!iDJ1Bi'ler цвет изображения (обычно цпе11'вксrа} ДJJЯ Web-зnе·
Мента }II1РaQления
Скорее всегC'l. эти свойства 'б)WYТ JVi.fl вас ПОН:НТИЫ. ТЭR что BJ\recтo примеров их
использования давайте немнОI'О сместим шщенты и прО:Верим в дейсТВии ряд 'эле
ментов упра8леНШI Web- формы ASP_NEТ.
Простые элементы управления называются так потому, что они являются Web-
элементами управления ASP.NEТ. отображающимися в стандартные НТМL-элемен
ты (кнопки. списки, гиперссылки. контейнеры изображений, таблицы и т.д.). Далее
мы имеем небольшое множество так называемых элеменnwв управления с расши
ренными возможностями. ДЛЯ которых нет прямото эквивалента среди НТМL-эле
ментов (это. например. с,з.1епdаr. TreeVi ew. Wizard и т.д . ). Элементы управления
для работы с u.cmoчн.икамu aaнHblX являются элементами, для заполнения которых
обычно требуется соединение с источником данных . Лучшим (и наиболее интерес
НЬПvI) примером такого элемента управления ASP.NEТ является, наверное, GridView.
Друтими членами этой категории являются так называемый "ротатор" и элемент
управления DataList. Элементы управления для контроля ввода являются сер
верными элементами управления, автоматически генерирующими JavaScript-код
клиента для про верки вводимых в форму данных. Наконец. библиотеки базовых
классов ASP.NEТ 2.0 предлагают целый ряд элементов управления, связанных с
решением проблем безопасности. Эти элементы интерфейса инкапсулируют все
особенности регистрации доступа к узлу, предлагая. в частности. сервис ввода и
получения пароля и по.цдеРЖl()' ролей пользователей.
При работе t' при:мероu.не забывайте о том, ЧТО элементы управления Web - фор
мыI иnиапсу.uирywт ВО3МОЖН'CIсти Т'енерирования СQОrnетствуюu.щx 1-.ITh1L-десЩi>ИЦ
торов и сдеЦ)'](}т модели Wщdоws Fonns. дi1a начала создайте вов.ое Web-прmю:иre
а:и:е ASP.NETc Н<W.lщmщм AspNe t Ca.r 55i..te ,
Этorо ()удет достаТI)ЧНО. чтобы ваш эдемент r1eTJU IЮ3ВQЛЯЛ лер.е.Йти н дРугим
с:гра:вицам УЭJJGi. ВblПDJ.II-ШТЬ Дi:шолнитeJtЫn,lе действцn в случае выбора ПОJIЫЮБа
тедем дално:ГО DytfШТЭ меню можно. с помощью обрабоТЩ1 со,быти.я MeoultemClick.
Для нщцего при:мера 'в этом необх:одимости нет, но цы; должны знать. что. с ПОМО
lЦЫ9 постуш:iюще.rО параметра MenuEvEj о tArg.$ МOOfЩО оцреДt"1IН1'I,. «акой пуюп
Me:f:!.JQ бьш выбран.
Работа с AdRotator
Роль элемента AdRotat.Cir ASP.NEТ защrючаеТqI в случpJ%ном отображ.ении 000-
брaжtJ~ в Нf)}\\ОТОРОЙ llШIИЦIm В окне браУ;Jq>а. Н~посредСТвенВо п.оме РЗЭМбще
PlИ:Я AdRotat0r в шше проеК1"ирования оltотоf5раящетс~ в Биде nycто,о·заместите
ля ·ЭJ.IeJ\l~НТа.. ~он.ально этот элемент yupqвлени)'l не сможет :ВЫПШI1-J,ят"!', свою
~адачу ДО п;х пор, лова ВhI не наэuaчит.е СВОЙСТ.еу АdvеI'ti s еmелtF'l-lt;, ОСЫJIRy-на
фa'ЙJI, {)цисывающий все изображения. Дли :mцщ:го примера источн:иком данных
будет дроtтоЙ XML-фaйJ1 С именем Ads. x.rnl,
Добавив этот новый XМL-файл в уЗeJJ. укажите Ц нем уни:калънъти элеменТ <Ad >
;ЩЯ JtaЖДОГо. изображения. :кcrгopoe требуетс:а О'Fобраз.итъ, }\.юf минимум. каждый
щrе-м:епl' <Ad> до.л:Жен указать изображение.для ото[)рЩfreНИ.R (Imag,eUr.l). адрес tJRL
дм пер~ода rrpи выб0Р~ данного изоБРaJI,еFЩЯ jТа rgеШrl ), те:кст, ПОЯIШЯЮЩИЙСН
при ра~мещеюm указатели м:ыши на I1зображеmrи (A1.t e rл.аt~Техt -, J'I ":вес" изо:бра
жеШlЯ ' l;Jrrpre·ssiO DS).
<ImageUrl>SlugBug.jpg</ Imageurl>
<TargetUrl >http ; / /www.Cars.com</TargetUr l >
<Al tеr'паtеТехt>Ваша новая машина ?</AlternateText >
<Impressi o ns>80< / Impressi ons >
</Ad>
<Ad>
<ImageUr l>car . gif</ ImageUr'l>
<TargetUrl>http://www.CarSuper·Site.com</TargetUrl>
<Аltеrпаt еТехt >Нр авится эта машина?< / АltеrпаtеТехt>
<Impress i ons>80</ Impressions >
</Ad>
</ Advertisements>
Теперь можно связать ХМL- файл с элементом управления AdRotator с помо
щью свойства AdvertisementFile (в окне свойств).
. указанные ссылки
IИnг создаНЮ; ~iiшы 'с~ооЙ мечты'
...
. ... ""....... -t- ,~ ~.. , _ _ "" "",,,,, - - - _ ~ ___ ---4 ~ О
_ _ _ _ _ _ " _ ... :
;\il""~' i :l htlp,!flocaJ,asfJ'lЗ6S/АSPNetсarsSitВ/~fauJt.~~х -
~ .,..-- _.'-- -~- . . " _. - - -~ - -- '~- ' •• - toд: , й
0 - • - ,;~; с] ПерехО4
r~ 'i:'Z"'Фt ....,..==,::;;;;;:-~~
(,Ы""~ .. ~ ~
_ _ _ ---::.......-......... J.-""":-__ ~=_
2. ВыберИте базу данных Сзrэ (ееnи потреб~ется.. создайте ДJlЯ этого новое со
единение).
~. __
~;; --- -- .-.----:1
... _,---- ~ - -." -..
~,
~_. . " о ~nontv_ r.-
I[ У!1ВЕ. .. ]
Oмake
О Color
I[ QвOER ВУ... )
O~-
~CT stetвmest,
J
_ [ Po:tr..-.:ed." J
<asp: G,r: LdVie'\~ 1 D= "Gr: i ·c!Y:1 e,w l" run<>. t=" зе.rVеr '"
АutоGепеrа:tеСО]I.lrnns'= "F~lse 1. CellPacЬ'1ing=' " 4 n Da taRey'bla1JLe's= "СагТ О"
DataSourCt!ID="Ca.rsDataSource" F.o.r·e Colo= " # зз.З·ЗЗ3" Gr i 'dLi nes="None":>
.. .. . 4
ТИп SqlD ataSo u rc e (новый в .NEТ 2.0)- это KOМIIoHeHT, инкапсулирующий ин
формацию о хранилище данных . С учетом знаний, освоенных вами в таве 22. сле
дующие атрибуты должны быть для вас понятными:
а:Ьс аЪt' ~o ~~ .~
аЬс .aЪ~ .b(i r EI1eb"ftiti1g ~
аЬс аЬс Г En6bJe DeIelIng
.г ШЫе:И!aIon
Е!~~т. ,~п.andDВRЕ~
Gвr.r_INsr.RT, 1,IPOA'Тf,"~~'b8$ed.1Ih \IOUr
SEIZC1~ , ~ou musth8V8,.J:II\м'!,~IIejd~ ~
фt(on. to~~,
О 'Ikй gPI:.IЦd8tJi:: ~
lIblfteOI U;I)A~ !I!'d 1EiElFIit.~,I8ItH" dlit'8I:t wh!lth8r' tII8~·
~~si'laldw.=·_~~tМ~, ТI'4$ 'heJps
Ph!I , ~. • '
oкll ~ ]
Рис. 23.27. Дl'lт.омат~ческое генерирование SQL-'Dператаров
<;'аЭБ":,.Sq1Dа ;t а S'оu :rс€:. ID= IICar sData.Sour.c e·' щtц;,_t=" serve r"
COnl}e~tiOJ1·St;r ing=
"Dat a SOI,u:::-е=-lосаНШS!:J lnitiai Cataloq=-Cars/ I.I1tegrated Sec-u.r it у='Тruе-"
1070 Часть V. Web-приложения и WеЬ-сервисы XML
Pro viderName="System.Data_SqlClient"
SelectCommand="SELECT * FROM [Inventory]"
DeleteComma.nd="DELETE FROM [Inventory] WHERE ICarID] = @original_CarID"
IпsеrtСOПDDaпd= "INSЕRТ lNTO [Invent ory] ([CarID], [Make], [Col o r],
[PetName]) VALUES (@СаТ1О, @Make, @Color, @PetName)"
Uрda.tеСОПll1\&пd= " UРDАТЕ [Inventory] SET [Make] = @Make, [C o l o r] = @Color,
[petNarne1 = @Pet Name WHERE [CarID] = @original_CarID">
</asp:SglDataSource>
Также будет присутствовать компонент Sql DataSourc e. который обеспечит до
полнительную разметку. определяющую объекты параметров ДJШ параметризован
ных запросов.
<DeleteParamet ers>
<as p: Parameter Name="original Ca rlD" Type="Int32" />
</DeletePararne ters >
<Upda tePar'ameters>
<a sp:Pararneter Name="Make " Type="Str'ing" 1>
<as p:Parameter Name = "Co lor" Type=" S tring" 1>
<asp:Parameter Name="PetName" 'Type="String" 1>
<as p:Parame t er Name="original CarID" Type="Int 32 " /> </
Upda te Parameters>
<1 D.sertParameter' s>
<as p:Parameter Name="CarID" Type="Int32" />
<asp: Pa rameter Name="Make" Type="S t ring" />
< аБР: Parameter Narne="Color" Type="String" 1>
<a sp: Parame ter' Name= "PetName" Type="Stri ng " 1>
< / In se rtParameters>
Заключительным шагом является разрешение поддержки редактирования и
удаления данных с помощью встроенного редактора GridView (рис. 23.28).
1~
EdI: Тerфiotes -.'+:J~~
...
,.
O H~ ~ о ~ ~G . ;) f»!<a il ~ e e · ~ .~ . :,',; I~ (1
"11>"'[; i~~~l~~~~~~~r;;~ ,.~ . _= ~_._~ - -rli G~- ctь;п,,,» '~.
- *-- - ~- - --.".. ~, - - - - -.- - - -=: . . -
Добро ПОЯQ)ЛОВЗТЬ В Саrз R U's! "'"
XoТ1rIe Slug Бug красного ПВe'fIl.{
3ах,щип: да bu-Supe.tsite.СОm1
•"
вмw Ull.em.r! Snakе
Vlpet lq>acJ!lМi!: ~P)' "
;fJI'
_ _ о ~~~~TЬ -- '--'--
'
I 8ыеритеe цает ш
2 У<ОJllиrе Н_.НИ_ [~J .' T~I. Выберит<! моАeJIb
З Ук"",ите АОТУ АОСТО"'И
~_~" <~~;t;i!у-)чr:~;r~~: /'-.<- .. j
!.''' AllowR.turn True
I ,. Enebl.Тherrтlng True
\.,. En4bIeViewSt!te ТПJe
5t.pType АUlО
~"rtI·······
.;.,)
~~
, ,"'
,
,1
ОК .1 I C.ncel 1
11 Пo.nyт.iеиие ~в.чеиий,
string order = striЩ:I,Fоrrr.аt(I1[ОJ, в-аш {11 [2}т Суде';) доставлен ,[3} . '1/
Итак. :ваш узел AspNetCarSite :готов. На рис. 23.31 noказан элемент Wizдrd з
деЙствйИ.
Пн ВТ ер 4 ... hT Сб ВС
22ШJш.12~'±
i.li1..i!i.шll
J.21Зl1.J.S1illJ.fl
.12.:2.0~ШnМ~
Шi.1Z~п ~m 1 ~
Э. .:1.s.~1~2
- - .
I ~D1'IY.T~t :l\" ti~ _1
ИСХОДНЫЙ kOA. ~айлЫ AspNetCВrsSlte размеЩены 1'> подkаталоtе~ соответствующем главе 23.
1074 Часть V. Web-приложения и Web-сервисы XML
l
""
Control ToVa lid.ate Чит-ает или устанавливает имя элемента yn,равпениJt, который необ·
жщимо контралирOlJ'ЭТЬ
:JeryJlll]lШ1В _РIrЖВНИI!;
r-- .- ~;Бi',~;l1'f д",йt'ТЕШ1\!:]{Ы,,~ ~!Н\"tЫИL\" '(!:Ь 2БN
Элемент RequiredFieldVaHdator
ffi:iСтроИть RequiredFieldValidator очень просто.. В окне СВОЙСТВ Vis.ua! эtшi1а
2005 установите для СВОЙСТВ ErrDrMe.sBage и CGntrolTaValidate 'IJYжыые значе
НИЯ . Определение *.asp.x ДОЛЖНО быть 'ГаКИМ.
Элемент RegularExpressionValidator
Элемент RegularExpressionValidator может использоваться тогда, ногда тре·
буется сравнение введенных символов с некоторым шаблоном. Так. для гарантии
того. что поле данного Tex tBox содержит действительный номер социальной стра·
ховки США (US SSN). можно определить элемент так. как предлarается ниже .
ковому шаблону. "Указанное здесь выражение " \d {3 }-\d {2}-\d {4}" соответствует
стандартному номеру социальной страховки в CIUA имеющему вид ХХХ';<Х'ХХХХ (где
х означает любую цифру).
Это KOНI<peTHOe регулярное выражение вполне очевидно. но предположим. что
нам нужно проверить соответствие действительному телефонному номеру Японии.
Выражение, необходимое в данном случае, является более сложным - оно имеет
вид" (O\d{ 1, 4) -1 \ (O\d{1,4) \) ?) ?\d{l, 4} -\d{ 4) ". Поэтому очень хорошо. что при
выборе свойства ValidationExpression в окне свойств вы имеете ВОЗМожность
выбрать подходящее значение из встроенного набора часто испольэуемых регу
лярных выражений (рис. 23.33).
Замечание. Если вам действительно нужны регулярные выражения, то знайте, что платформа
.NEТ для программной работы с регулярными выражениями предлагает два пространства имен
(System. Text. RegularExpression s и System .Web.R'e gula rExpressions).
•
Stondartl""Фl'Мs/on$:
,~~~;t\XL~-~d~-- '- " --- -- -- -- -- ---- - .- ---~1
! R.~,C. pt,;пe nlJmw ' :1
,Я.R .С. D()S~~I code I
IР;!! .С. 500.1 setш~.,· t!шmber (JD "urт1ber) iIII,:,i!,J
tni1&' ..,;~~
=_ __
J.l.5,
\f~1OO о.""я1tJn :
;~{~t:\df21-\df<I} -~ =--_-~ -~_: .. ___ ~ J
Элемент RangeValidator
Б дол{)лнение k свойствам Mi I1.i ffilШI Vаlu е и Мах i ni u тУ а } u ё. элементы
R аngеVэ lida tor имеют своис'l'ВО Туре. Чтобы :ВblIЮЛНИТЬ npOBep!ty ввода ПОJ!Ъ30ва
тем на соответствие ЗВДaJ-ШОМу дйa.naзону целых чисел. ДЛЯ этап) сво.йства.нужш;i
указат.ь Iпt е g еt (что не ЯВЛЯе'Гся эначеl-шем по умолч:аниюIJ .
< а$р : RiJi.fJgeValidat o r JD"," Rёщ g9Val idaJ:: o r J " r'LТ:Г1 Ю t = " s e rve!:"
Со.] t r o;l'1'~Vali.d3 Ье =" txtRang e '.
Е!т оr!1<:'!ss аg'е=l'IВ:&едите з:н.а'У'еН Ие между О и 10 0 ."
И21.:в:iInumУа1uе="!ОО'·' Мiцim:WnValue="O" 'r~" Lnteqer">
<'" а зр: fl.angeVal ic"lalt.cr>
Элем~нт HangeVa 1 idator можно иёпальзовать и 'Тогда, жогда нужно npовери.тъ,
что введенное знаЧе}пiе при.иaд.iIеооfТ заданному дnапазоцу денежных значеЩf.Й,
значений дат. чи· (;е,)1 с IШаваЮЩеИТQЧКОЙ ИЛИ CTpOKOBъ:rx. Д'aшJ:ЫХ (это 11 еСтЬ значе
ние, уст<Ыавлимемое пО' умолчанию) .
Э.nемент Compar:eValidator
Наконец. обратим ваше внимание на то, что СоШра.lеУа lid a.t Ci r поддерживаe-r
свойство Opera:t ar.
< азр: Comp<J.,!:' ",'Ja 1 idцtоr ID= "'Compar<;rVal idat-orl" r .1J1 a t=" serv€·r" 1
,C<:;rfl tJrc. .lT~ \]", lica i;;e= '.' txt C-ompa.r i .soJ.:l "
Еr r·Сirм:еS.5,аgе="ВэеД lilте зна че ние , Me f1:bln.ee 20.'"
OpQ.r atorr="lieSS!l'han" Val ueToCQmp«,re=" 20 '.'.:>
</ а sp : С ошра l.tVal .Lda tGI:'
Поеволъку задачей это.го элемента «онгроля :ввода является сравнение 3На
че-НИЗ. в текстОвом блоке с другим значением при помощи бинарного оператора.
не удивителыш ТО', ЧТО свойству Opera tcr можно назнаЧйтъ такие значеюш. как
Les,s'Tha о (:менъ111е) . GX'E!cJ te:c1' h.a 11 (Ciолъше). Equa l (равно) ~! No t:.Eq ual (н:е равно} .
Также ЗilllJе ':гьте, -что ДЛЯ ув:азания значения, с RОЛDР:ыМ nPОИЭВОДИТСЯ сравнение .
испо1lЪ3Уется Val HeToCO!I1f"are.
1078 Часть V. Web-приложения и Web- сервисы XML
Первым шагом при этом является добавление Vа lidа t iОП SUПlmа rу в файл
* .аБРХ. Дополнительно можно установить свойство HeaderText этого типа, а так
же эначение DisplayMode. которое по умолчанию задает представление сообще
ний об ошибках в виде списка с буллитами.
Резюме
Создание WеЪ-приложений требует иного подхода по сравнению C1ieM, 1ЮТор'ыЙ
испощ,6Устс,я д;пя создШЦlЯ " 11'здициqдщ,щ" приложенИй:. В начале этой тлаяы: быn
преЩIQЖен краrnий обзор фуццам:е;нталъвщх ~оставлюощих Web-разрабоТRИ, :н; КО
TOP:J>n.t можно ОТНе<?ТИ НТМL, НТГР. сценарии :клиента .и сценарии сервера ripи ис
ПОJIЪЭОISЗНЦИ клаСЕ;;ичесщэй 1WQIОЛОТИЦ ASR
3вачитеJil>Е.аЯчастъ f1l8Вbl б:ьща n:ОСНJiJlЦeJ-Щ рассмc.r.rревию архитектуры страви
ЦЬ1 ASJ'~NE't I$I увидeJПf. -что с' I~a:щдым файлОМ ~ . а $'РХ в пр~~те связан нeJrowoрый
!ti1acc, производньтй от System.Web.UI.Page.. С помощью 1'ажото подхода ASI'.1\ТEТ
поаволяет строить более рриroдные ДЩf мнШ'окра'~-ното использования системы.
соответс~ующие:npинципaм ООП. в этрFj тл~е раесматрив:ал.оеъ TaIOll:e ИQПодь
З0в;;щие щаблонов стрaJ:Ц'Щ щ Рa3ЛW'JДЫХ WеlrЭЛ5ментов управления (ШLПЮЧая но
вые типът ,G.r i d\view и Wiz.a r d). B~ моти убеДКIЪCЯ 1'1 ТОМ. что эти элементы rp.aфп
ческоro щггерфейса отвеЧJ'Щ)Т За создание ЩJДХОДЯЩИХ деснршггоров IП'МL-:кода,
l.Iапрaщrшмo.rо клиенту. Элементы контроля ввода ЯВЛЯЮI'ся серверными элемен
T~, :tra которые ВОВJЩГается щ!д!!ча подroтовки Java&tipt-Jtoдa :к.nиента длн .вы
полнеJЦIЯ apoBeplU,r дoцrcтимостi1, введенных в форМу да:tшых. чтобы уме;ньШить
КQmlЧес.тво н~бходимых обраще.l;1И.Й к ct';pBepy.
ГЛАВА 24
Web- приложения
ASP.NET 2.0
Проблема состояния
В начале предыдущей главы было yRазано, что НТТР является сетевым протоно
лом, не обеспе"-швающим сохранение состояний. Именно этот факт делает процесс
разработки Web-приложений столь отличающимся от процесса построения вьmол
няемого компоновочного блока. Например. при создании приложения Windows
Forms вы можете быть уверены в том, что любые члены-переменные, определен
ные в :классе формы. будут существовать в памяти до тех пор. пока пользователь
не прекратит работу выполняемого файла.
нем userFavoriteCar.
public partial class Default Page
(
/1 ДаНИilе состоRИИR?
private string userFavoriteCar;
Обработчик события Click сервера для кнопки Указать ... позволит назначить
СТРОКОВУЮ переменную в соответствии со значением TextBox.:
protected void btnSetCar Click(object sender, EventArgs е)
(
11 Сохраиение ииформации о машине.
userFavoriteCar = txtFavCar.Text;
а обработчик события Click для кнопки Прочитать ... будет отображать текущее
значение члена-переменной в поле элемента Label страницы.
protected void btnGetCar Click(object sender, EventArgs е)
{
11 Присваивание тексту иадписи зиачения члеиа-перемеииоЙ.
lblFavCar.Text = userFavoriteCar;
Замечание. Эта проfiлема касается не 1'рЛ!>КD ASP.NE1 Geрв'Петы Java, COI-, " класСические" ASP-
и РНР-при:ложения - !tceM этим технолоtИЯМ таr<жe hриход\ltтC1I решат!> проблемы управлеt'lия
состоянием .
p r o t€-c t .ed vQid ,b tnSe eCar...:t::11 C' k (Qbj E:c t S е'л d е. у, Б:V·~п.t A.rgз е,)
{
Se s·!!'j:Qn ! "-Us~rFаvС а r"' J = tхtFэ\rC,3 :t. Tex·t ;
}
р!' ,з t e-c ted 'lfQ l.d btnGetC a r'_ С1 i c k (.o bj ect sencle r ~ Еv еп tAt g s eJ
{
lblFavCar.Text == \st r iпgISеs s iоn["!Jsе.:rhvС аr "J;
1
11 д,ля в'l"ор~чвоХ'о оБРЦUЮJJ: серверу.
Тбl1ерь, ИСПОЛЫJyИ OJ{fiO свойств V1Sual Stu..dio 2005. ПОлуЧИrz'е доступ к свойству
:Ltешв и добавьте:в l,i s tBo'X чеmрезлемента Llstlt.em. Ре.зультат должен быть
примерно Т3RИМ.
<irlpu t t уре=" h i
dden" name="VIEWST1\.TE" l d='; 'ilIEWS'I'A ТЕ" \Та 1 це= A/wEPP-..у
~:1Мjсmс2!NnЩkOXDNIW5+R2VDbNWtEtНl!Of+-Уfutvu=" 1>
Замечание. Страницы ASP.NET резервируют небольшую часть СТРОКI1 VIEWSTATE для вну-
треннего использования. ИмеltНО поэтому поле _VIEWSTATE появляется в браузере клиен
та даже тогда, когда учет состояния представлений отключен для всей страницы (или для всех
элементов управления).
,
[лвва 24. Web-nРИJто*ения ASP,NET 2.0 1'087
И'сходныи КОД. Файлы примера VlewStateApp рc;tзмвщен:ы в ПОДI(~талоге. соответствуtOЩS~ таве 24.
A~
1".
Class Style 50eet
Web XMl Fil. XMl 5ch~ma Text Flle AssembIy 5Ql D.tabase DataS.t Generlc
configUrati ... Resource F~e Handler
~ ~ ~ .~c:'~ ~\
Site Мар
l, Cry<tal Report Mobile Web
Form
VBS<riptFile Report JScript File Moblle Web
US;er Сопtrоl
Mob;le Web
Ccrlfigur dti,.,
r А~~J;;'t;;;~-';~~А~~;'е;;=,=с~t'=-"'~- ~.,,-,с~,,,с,,,='=-=""-"'" =,.=-'--~... =~ . .=,c~,. =,=- -'-""С'С· -,,-с.%~,'З .,
.•."" _ _ ~~ " _ _ _ _ ~ _ . _ .,,. _____ ",,, __ __ ~.,,,. ,,,_" ~ ' ''''' _ ' _ _~_ _ .,._,.
,
~ ~. . ~_._-e......., _ __ ---,,-,.; ~ , . -, ~,;, _ "-".....< ,, ~"':""'
______ ____ __ • _ _ _ _ _ _
,_ " _~.~ , _. _ ,_" ~ . ,, _~.
• __ __ _ ..
~ ,,_. ~_
г
~
~
-
~
с
.
.
с
-
-
-
-
-
-
~
-
-
-
-
-
-
~
. Global.asax
{ .. __ ".. :~ •.• _~~ ~ .• __ , .,. ~~. ~ ..........."'-,,.;. ..... ~'''<, .• ,_,c _---''-" . ~ ,'~ ~," ~ ~~ _'- _
г-,~ - -- , -"",---,~",~,- , ~ , - - -_...-
i Virual
...
I . _:~'
с# ~;~_·:~. ___ •. _ __ . __.,•• __ • .о _ _ с _____ с __ .. . ..
Add I[ Сапе.1
</s-zrjpt>
Аррl :iJca tioГl_Error () Глобальный Dбраf'JОТ'lIllК ошибок, КQТQР~И 6!>.lЗываетоя TorAa, IФгда
Web-ЛРJМJожени~ геf1ерирует необработанное ИСk<.I1iCчеНие
1090 Часть V. WеЬ·приложения и WеЬ·сервисы XML
Свойство Описание
Application Позволяет взаимодействовать с переменными уровня приложения, используя
доступный тип НttрАррliсаtiолStаtе
;, .....
СеансА
(Ht,t pSessiOn$!;atef ·
"
CeaflC
(BttpSe.ssionSt&te)
n ,
(- Сеанс В -~
(HttpSessionSta.tej ,
,
ЧлеН"1 Описание
appState t=
stгiпg.Fогmаt("<li>Наиболее популярный цвет: rO} </ li>",
appVars.mostPopularColorOnLot);
appState +=
string.Format ("<li>Наиболее успешный продавец: {O}</li > ",
appVars.salesPersonOfTheMonth);
lblAppVariables. Text = appState;
Открыв сейчас эту страницу. вы обнаружите, что в поле типа Label страницы
отображаются строки каждой из переменных приложения.
Замеlfsкие. Во МНОГОМ аналогично оnер.атору la.ck Б С#, если после В.ЫЗ0ва Loc·k () , но перед
ВЬJзt1ВОм Ппlосk () ВОЗНJJII(нет Иf!КIlЮ L lеff\<1е. БI10КИРОВf(Э буде'! <)~щ'матичеСJ(И удалена.
И'СХIiIД"WЙ КОД. Файлы пр~мера AppState раЗМБЩЕ!НЫ в ПОДRаталоге. СООТfjеТОТ8ующем главе 24.
Кэш прилож:ении
AsP.NET предЩlГЗет \7Щ~ од.ин. БРлее r:ибкий MC:tOA обработRи данных уровн.я
прmюжения. Вы, KOHe~o, ПОМFI.И'1'е. что ЭН:э"{ени.n оБЪeRта НttрАррli' оа:ti'О1lS,t;;зtе
остаютсЯ В паМятц ДО тех пор. покаработэе.т wе-Ъ~цриложение. Но иногда требует-
00. чтобы хавой-то фр~ент данных приложel:1ИЯ :подцерживался только в тече
ние определенного ОГрЩlИЧе1ЩОГО периода времени. Например. вы можете 'поТре
бова:rь. '!!ТобbI создaнн,blЙ ТJjfЩ QataSet оста:валсядействителъным ТОЛЬКО в течение
пяти ми:вут. После ::П'ОГО вы предполагаете nOJJyЧ}1ТЬ новЫЙ тип .D.ataSet. ~Iи'ты
"Бающий возможные ДОЛЬЗQвательсЮ!(! мьд:ифииаци:и. Конечно. ВПОJlПtJ вОзможно
построить тai'УЮ структУРУ с применеnи:ем fJttpApplit:ationSta,te 11 некоторого
"ручного~ управл.ен:ия. но С'оответс-rвующая задача СИJI1>НО упрощается. если И'с
полъзовать в:эm rфиложеnия .ASP.NEТ_
1096 Часть V. WеЬ·приложения и Web-сервисы XML
Кэширование данных
Рассмотрим простой пример. Создайте новое Web-приложение ASP.NEТ с назва
нием CacheState и добавьте в это приложение файл
Global. asax. Подобно перемен
ным уровня приложения. определяемым с помощью типа HttpApplicationState.
тип Cache может содержать любой тип System.Object, а его значения часто за
даются в обработчике событий App l ication_Start (). для нашего примера целью
является автоматическое обновление содержимого DataSet каждые 15 секунд.
Этот тип Data Set будет содержать текущий набор записей из таблицы Inventory
базы данных Cars, созданной нами при обсуждении ADO.NET С учетом этого об
новите свой тип класса Global так, как показано ниже (сразу же после листинга
предлагается анализ этого программного кода).
11 Заао,nвекие DataSet.
SqlСбniN!сtiбn ·ел =' n~"" Sq1СогшесtiQ!1
("da t IЭs O\:Jr'ce=loc,a,lhogt: initia1 catalgg=Cq.rs: ив е !' id ='sa' ;:p~д=" ");
Sql DataA.,japter dAdдipt =
nе .... 9qlDa ta.AaapteJ: (" Select '" ~'rom rn veI).t bry'·. сп j ;
Da'ta $e.t :t.rl.eCa:r:; = new DataSet () 'i
dAda p t. F'ill (t.hеСа,rэ' , т. Inven'u;;,:y"') ;
If C~~aa"lpfe а хэше.,
t.heCa lZ.he .. Iпsеrt: {".AppD,H.aSet ".
t-hеСаrs' , Г1\111.,
DаtеТimе , .Nо·w . .Ad!:JSесоndз (15) г
Ca,C[I·e. N.05>1 idi.ngE·X piration,
CachaItemPriority.nefauJt,
1'J!S!'w Ca.cheltemRemovedCallbcaek (updateCar ln'lentoxy)) ;
</script>
С:наЧ2lЛа 'обратите внимание на то. что тип Gl"ba l onp:eдмяe't статическ-ую П~
ременную типа CO!ctl€. Причина в том, Ч,тоодредеЛiIетCJi та.н.же С'те.тичес.кая ФУНК
ЦИЯ (i]pdateCa rlnventory () j. которой тpe6yeтc~ дaeтyn 1с Са с:Ье (нanОМИйI.1. что
Сl'<\т:и,:ческие Чllены :не имеют AocTyna к насл~дуе~IМ ~Haм. поэтому в да:ннрм
случ;ае ВЫ не сможете использовать свойство 'Соnt 'ея t).
Внутри обработчИRa событий AppliQ.Q:ti,:;n_Start (/ заш:mнле1'СН ТИТI Il8.ta.Set.
RОТОРЫЙ' затем помещается в кэш приложенил. ДОЮ1WО БЬiТЬ пена. что метод.
1
I
1098 Часть V, Web-приложения и Web-сервисы XML
// Сохранение в хэме.
tfJeCache. 1 nsert (" AppDa taSet" , 1 / имя дли иден'J!ИфИICЗЦИИ элемеН'1'i!I.
theCars, 1/ Об<ихт ДnИ отnpuJCИ В КЭШ.
n и 11 , /1 Зависимос'J!И ДnИ об..еJCТi!I.
DateTime.Now.AddSecollds (15), // Длительность npеб-ываиии вхэше.
Cache. NoS1idingExpi ratioll, 1/ Фиксированное или CJConьзищее время.
CacheltemPriority.Default, 1/ Приоритет элемента .
1/ Деле~i!lТ дnи соБЫ'1'ИR СасhеltemRешоvе.
new CacheltemRemovedCallback(UpdateCarlnve ntory));
Первые два параметра просто формируют пару "имя-значение" злемента. Третий
параметр позволяет определить тип CacheDependency (который в данном случае
будет равен null, поскольку у вас в кэше нет элементов, зависЯIЦИХ от DataSet).
Теперь при запуске приложения тип DataSet будет заполнен и помещен в кэш.
Каждые ]5 секунд DataSet будет очищаться. обновляться и снова помещаться в
н:эш. Чтобы увидеть результат этих действий. мы должны создать тип Pag e. кото
рый будет поаволять некоторую степень взаимодействия с пользователем.
i!.IoMcp,r
~eTr
,
1" I 1, , 1 ' , ,' , , ' ,), ,"
аЬс ~bo
PI:otE:t:ted' vc>id ЬtпДddi;:а]'_ CJ.:i<J k ('obj e.ct sende:r, E",e,n 'tArgs е')
r
1/ Обиos.оиие "a~ :tn\!'entory
1/ и Jlызаa
Ref'reshGrid О .
SqlCo'H fI,ection сп = new SqiCt:lnnectlOlJ () .-
СП • Connect iот,stтiцg =
'tT)ser .lD=sa; Pwd=; Il'litial 'Catalog=Cars i ,Da ta зоuгое= (10c,al) ";
.сп
_Ореп (). ;
string s~l;
SqlСОШll'аnd сшd;
1100 Часть V. Web-приложения и Web-сервисы XML 1
/ / ВС'1'&IIха Ho.oro Car.
sql = string.Format
("INSERT INTO Iпvепtоrу(саrID, Make, Color, PetName) VALUES" +
"('jQ)', 'jl)', '(2)', '{З}')",
txtCarID.Text, txtCarMake.Text,
txtCarColor.Text, txtCarPet Name.Text);
cmd = new SqlCommand(sql , сп);
cmd.ExecuteNonQuery();
сп. С1оэе () ;
RefreshGrid() ;
Исходный код. Файлы примера CacheState размещены в подкаталоге, соответствующем главе 24.
Глава 24,'Web-(1риложеНИIl A:'SP.N!;T 2.Р 1101
<J.scIipt>
Подобно типу HttpApplir:ationState. тИП Ht,tpEes$ionSta-t.е может оодержать
люБQЙ ТИП. ПРОИЗВОДIiЫЙ от System.Object. ВRJmi)Ч'ая пользовательские Шlассы.
Предположим, например. что у нас есть ROBIiJC Web-приложение (Sessi"-'I'lЕ;tаtе]. RQ-
TDpoe определяет ВСПОМОN:rедМ-lЬ~Й I<ЛaСС с имвдем UserSboppingCa.r:t..
tеансовые состоЯния
fJapx~! f'
itре~иг.r
:t- .АревдВ!
~aтa достamc.и: I
l bi U..!ie :rID . TeX't = s .t r i..лg . ]i'o цoat ("'3 1+9 ',.ени.е .в.аше го l D : I O}",
3е ;s: &i О D . .5 еsз i.оо IЩ;
Методы Re'mov,e () и
Remove All ~ 1 можно ИСПОЛI:,3Qвать д!.Щ удален~.~ элементов
из экземпляра Ht.tpSes.sicmState пОЛЬЗОВаrrеля.
ffi.€.·ss i o1'•. Rerno-v'e [" н е.ко 'Горы:еУ'жеНен~жныеЗЛ'ем€'нты" ) ;
Замечание. Чтобы не менять значение Timeout каждого пользователя, вы можете изменить при
нятое по УМDлча~IИЮ 20-минутное значение для всех пользователей сразу с помощью атрибута
Timeout элемента <вessionState> в файле Web.config (структура и возможности это·
го файла будут рассмотрены в конце главы).
ИСХОДНl,IЙ КОД. Файлы примера SessionState размещены в подкаталоге, соответствующем главе 24.
Данные cookie
Последней из рассмотренных здесь технологий управления ДaJЦiъrми состояния
будет использование данных cookie. которые часто имеют вид обычных текстовых
файлов (или наборов файлов). сохраняемых на машине пользователя. При реги
страции пользователя данного узла браузер проверяет, есть ли на Manrnнe пользо
вателя файл cook.ie для данного URL. и если такой файл обнаруживается. данные
файла присоеДШJЮОТСЯ к НТТ'Р-запросу.
Получающая запрос Web-страница на сервере может прочитать данные cookie.
чтобы использовать их при создaнщi графического интерфейса, учитьmающего теку
щие предпочтения пользователя. Уверен. при посещении своих любимых Web-узлов
вы эам ечали , что узел как будто знает, какого сорта содержимое вы хотите видеть.
Например, при регистрации на странице http://www .minJstryofsound. сот мне
автоматически пр~ъявляется содержимое. отвечающее моим музыкальным вкусам.
Причиной (отчасти) mшяетсл то, что на моем компьютере бьщи coxpaнeНbI данные
cookie с ШJформацией о том типе музыки, которую я предпочитаю слушать.
Точное место хранения файлов cookie зависит от используемото вами браузе
ра. При использовании Мicrosoft lnternet Explorer файлы cookie по умолчанию со
храняются в папке C : \ Documents and Sеttiпgs\<имяпользо:sателя>\Сооkiеs
(рис. 24.6).
Содержимое конкретного файла cookie, очевидно. будет зависеть от URL. но это,
в конечном счете. обычные текстовые файлы . Поэтому вариант использования
данных cookie нельзя считать удачным для передачи конфиденциальной информа
ции о текущем пользователе (например. номера кредитной карточки, пароля или
1
Глава 24. Wеь·приnожеtfия ASP.NEТ 2,0 1105
дрyrой анадогичдой информЦДИ:И). Даже если данные бу.lJYТ зашифро.ваны. какой
Шlбу.nъ хакер Mon~tT ра('ПШфроватъ сооrnеТС'ГDующие Эl'Iaченин и использоrщ:rь юс
в злонамеренных целнх, Но. та:н mm иначе, фаЙлы cookie :играют B3iK!iY}O роль в
разрабо:wе, Web-прилощециЙ. поэтому нам ваЖ1:Iо выяенитъ. Ii'.ai( эта специфиче
ская ТeJUIОЛQГия. ynравJJЩЩJl ,состоянием отражается в ASRNEт.
"~~ вacli.
'W - , , 1>;,
~!1
.1
1..
~) SeэIW
.г'
I i r--olders ?!Г.
~
1>t.\Jм",>, fCsG~\PQO~~~:JNTmTEo.;\p;'~;S -
- FjI~<1IIdFlildeJl;,sk~ ~Ii_ 1c :a~---EI - -ti
.::)_ ~ ~,,_~.. f",~r
d
-
~~t<*fe.·'h.
' J:МIXeb
~ ~1'!:h/9 tЩ,
' Р.ис.:24,.6. данные oooli;ie. сохраненные ' БРa)lзером Мicrоsоft tпteгnщ E)(plurer
Замечание. БОЛЬJШ.fflСТВО БРl!у~еров I1Qддержив.ает СТрОkИ cookfe ДЛИНОЙ ДО 4096 б'аYtт. ИЗ-3З Т8-
КОГО ограlfИ'lения отроки сооlt.iе лучше всего ИСПОЛЫЭО~ТЬ ДЛЯ :за!Т"1МИНэ.ttия небольших фраг
MeNTOB данны •• например идеНnjфlllка~юров пользователей, С ПQl)ЛОЩЬЮ КОТОРЫ1( затем МОЖ~IO
ПОIlУ'IИТЬ допdЛн~тельные дaWHble 143 базы Aa~IHbIX,
Следует знать о том. что данные cook:ie не будут сохраняться на жестком диске
пользователя, если вы не укажете явно дату истечения срока действия этих дан
ных. используя свойство HttpCookie.Expires. Поэтому в следующем фрагменте
программного кода создаются временные данные cook:ie. I<oтopble будУТ уничтоже
ны. когда пользователь прекратит работу браузера.
. . . ~ ~T ' _ с:...-.
лобиwыйнiIПI<ТOК D3 еЛеный- ча.йо 1 ос а 1 ho,t-/iiiО24 о ]0·5'33181.44 П29993 98БО 34]-89557ZBIi2 -9794 207 D· iI- -
un ~~ fItIA ~• •_ C8I:iМ:
, ~
Данные cookie
г. - . _ -~ ~--- - ~
З'начени ~ _Cc('>Qk!ejA !
Исходный код. Файлы npимера CookieStateApp размещены в подкаталоге. соответствующем главе 24.
<?xml version="l.O"?>
<соп figuration xmlns=''http://schemas.microso ft.coml .Net.Confi gura tion / v2 . О" >
<appSettings/>
<c onne c tionStrings />
<sy stem.web>
<compi lation debug="false"/ >
<authe ntication mode="Windows"/>
</s y stem.web>
</co nfiguration>
Подобно любому файлу *. соп f ig , в файле Web. c o nf ig определяется корневой
элемент < configuration>. В его контекст вкладывается элемент <system.web>.
который может содержать множество дочерних элементов. с помощью которых
осутцествляется управление поведением Web-приложения в среде выполнения.
BASP.NEТ файл Web. c onfig можно модифицировать с помощью любого текстово
го редактора. Некоторые элементы. которым позволено присутствовать в файле
Web.config. описаны в табл. 24.4.
Замечание. Чтобы выяснить подробности формата файла Web.config, выполните поиск разде
лов документации ,NET Framework 2.0 SDK, соответствующих ключу поиска "ASP.NEТ Settings
Schema".
J
ГлаВfl 24. We-Ь'nРI1J10жения ASP,NEТ 2.0 1109
Табnица24.4. ПодборкfJ. элемеl'п:оа файла WеЬ.солflg
Э:пеllенl' Оомсанме
<ttaoe·
enahled=" t I f,c.l se·f'·
!:1J€'
J ocalQr)ly= "tr1.,le l:f а 1 'Эе.ll
page.output="Uue lfalse"
rечuеst1iIni t='" iпсtеgеr"
tt'<:)СБМОdе="' $оrtВуl'ime I S.оr .tБуС.з te:q.Q ry" j >
1110 Часть V, Web-прилож:ения и Web-сервисы XML
Вспомните из предыдущей главы, что с помощью диреl<ТИВЫ < %@Page %> можно
раарешить трассировку отдельных страниц. Но если вы хотите разреnmть трасси
ровку для всех страниц Web-приложения. измените <trace> В файле Web.config,
как показано ниже.
<trace
enabl.d="tru."
requestLimit-"10"
pageOutput-"fаlsе"
traceMode="SortByTime"
localOnly="true"
/>
J
Глава 24. Web-ПРИЛDженloUI ASP.N:Ei 2.0 1111
администратора GИ~'rемы И. например. еообщение (; из.винениямиэа доставлеННЫе
ПОЛDSОВ;:tТелю Н:еу~()бс:гва. В'J'ОРОЙ: файл [Er rQt:,40·4,ht.m) - э1'(J полъзовательс:кi1Я
страйица ошиБRИ. !(оrrорая должна nоявлятъсsж Т(i)ЛЪRотогда, когда среда выnoд
Ii~ЮLЯ о:бнарУЖl.ffiает ошибку с номером 404 (rpО3;ЕЩЯ ошибка ~не()бнаруженного
ресурса"). Ес:л:и ВЫ х-отяте.чтобы все ошибки обрабать1Ва.1ШСЬ этими пользователь
СКИМИ страницами. вы МОЖe'I'е изменить файл Web_config тш{, I<a1( предnarаeJ1СЯ
:ниже.
<sessionState
1IIOde="lnProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlСоппесtiОПStriпg=Пdаtа source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timеоut=П20"
/>
Принятый по умолчанию режим хранения оказывается вполне подходящим
только в том случае, когда ваше приложение обслуживается в рамках одного Web-
сервера. Но в ASP.NEТ вы можете дать указание среде выполнения обслуживать
*.dll сеансового состояния в суррогатном процессе. называемом сервером сеансо
вого состояния ASP.NEТ(aspnet state .ехе). Тем самым вы можете вывести *.dll
изaspnet wp.e.xe в отдельный *.е.хе. Первым шагом при этом должен быть запуск
службы aspnet_state.e.xe Windows. С этой целью введите в командной строке
Desc:фtion :
PrQ~ lIЦ)P(!rt for out~f?OQOS$
SeSSIOn sliJtn for ASP.м:r. If this
Иf'oIia Is~, QJt-<>f~
r.Q.Jes~'" notbo prOCCSO<!d. Iftris
<sessiet1S'tate
JDOa.=" Bt.a~8erv.6r"
s-t аtеСОIl1'.€<сt:LоnS t,r i:пg="t'срiр= 12 ~. 'О' . О.1 ; 42~ 2 4 '1
sql C p.nnec;-t-iорS-t ): iлg="-<:Jа t.a зоu :r:се=1.27 . (!. 0.1: 'l"ru.sted_ Conn scticm=yes"
CDD'k.iel еs-з="-fаl$е"
f '>
том, <tTO пользовательские данные при этом сохраняются наиболее надежно (даже
при перезanyсне Web-сервера).
Замечание. Если для хранения сеансовых данных используется сервер состояния сеанса ASP. NEТ
или SQL Server, то любой ПОльзовательский тип, размещаемый в объекте HttpSessionState,
должен быть обозначен атрибутом [Serializable].
AppliClltion:/CookieStateApp
CurтBnt Usеrl'l1аmв :INТЕRТЕСН\Д TROELSEN
Наследование коНфигура'Ци'и
Последним из рассматрива.емых в ЭТОЙ г.лаве вопросов будет .нaC:Jreдoвa.н.иe JCDtt-
фuгураЦ1Ш. Из преДЫдУЩей гла.эы вы узнали. ЧтО Wеь,.nPИ1I(J~ен;Qе МОЖНО· cmp6де
лить, КаЁ множество файлов, содержзщихсн 11 КOPI:IeDOM в:атзлЩ'е 11 любом ЧUСЛ~
н.еобязameльны:хnoдм:а~в. Все nPИЛО'""'е:ния примеров , ЭТОЙ Ji np~ды;цущеЙ таи
"Находились в ОДНОМ корневом :&аталоге. управlJН.емом IIS (с u.еQбя;~теJIьным :ката
логом Jlin). Одна1Ю ПОЛ}ЮМlilсштабные Web-upиложен:ия о(5ычно опредeляIОТ в кор
невом xaтaJioгe -r.шожество подкаталогов, нaждъrй из I«YJ;'0PЫX сод~жит некоторое
под'множество !свнзa.шtых Между собой файлов, Подобно ot;iЫ'-шому nриложен:ию д.пя
наc:roпъиоЙ системы. это делается ДЛЯ -удобства раэработчИIЩВ, поскольку .иерар
хичеСКaIiI струнтура может сделать БОl1Ъшое мдощество фащщв БО:1J~ ПOFI.JI'1'НЫМ.
Если,у:вас есть WеЬ·IIpйд:оже'fIИе ASP.NE'f. сод~ржэ,щее необязаТeл:blП:iJе ПЬДlшта
л.оги в корневом каталоге, m.I с удивлением обнаружите. что ка;недый такойподка
талог может иметь собственный файл Это
Aaecr ~~оЖНостъкаждому
Web.con'' fig.
подкаталогу переопределйть установки родительского Jta.T;'I.IIora. Если пOДt:щтал.оr
не .имеет CBOёrO ПОJI!baо;аателъсщ)го файла Web.config. катало!' tЩСЛf'i..дует'установки
сле~ фafu-ш. WеЬ. со п fig, размещешlOГО выше по CТPYJ:nYpe Шiтмат-а. Такой
ПОДХОД , Е8$ это .НИ СТРIilШО айуЧИт,. поз:воллет перенести оцредещшные Dp):П;щиm.1
ООП на CTpyКrypy 1Шталоrов. Соответствующая концеnцця щm:юстрируется схе
мой, npeдставлен:нdЙ сШ рис. 24.12,
1 I WеЬ · [lрмпожен~
,ЭамеЩlние. Вспом ните из тавы 11, что файл ma сhiле. cGrlf ig опре-деnяет раЭ)JИЧiiые установ"
ки на у;ровне маWIAНЫ, многие из kQТОРШ CЩlзаtlы о ASP. NEТ. 3Т01 файл ЯВЛЯErrqя наивысшим в
иерар)l.И~' наСJ1iЩОfЩНИЯ конфигурации.
На этом наш обзОр ASP.NE'I' завершается. как уже Ul!);цчерки~алосъ 'в rnаве 23.
полное и исчерIIl:olвающее рЗССМО"Грение A8P,NEТ ~.O требует отдельнqй и доВQЛЫЮ
объ'СМНоИ I{НИТИ . Но .11 надеюсь. 'Что~еперь вы ЧУJlСтвуете себи дос'raТQЧRО уверенно
в paмrкax соответствующей I1potpaмIOiой модели:.
1116 Часть V. Web-приложения и WеЬ·сервисы XML
Замечание. Если вам требуется более глубоко изучить ASP.NEТ 2.0, Обратитесь к книге Мэтью Мак
Дональда и Марио Шпушта, MicrQsoft ASP. NEТ 2. О с гтримерами на С# 2005 для ПРОфессионалов
(ИД "Вильяме", 2006 r).
Резюме
в этой главе вы имели возможность расширить свои знания в области ASP.NEт,
рассмотрев возможности использования типа HttpApplication. Вы могли убе
диться в том, что этот тип предлагает целый ряд обработчиков событий уровня
приложения и сеанса.
ния данными cookie и изучен кэш приложения ASP.NEТ. Наконец. был рассмотрен
набор элементов. которые могут присутствовать в файле Web.config.
L
ГЛАВА 25
Web-сервисы XМL
РО,ЛЬ Web-сервисов _
XML
с точки ЗРения самого ВЫСО1(ОГО уроВШI вы можете опред~ WеЬ-сервис XМL,
-кш: ~дивицу проrpaммlЮГО кода. ДОС't)'ЛНYЮ Д11JI вьrзо:ва с ЛРJlo{ОIЦЪЮ l:lTTP-запросов.
Однако , в отЛИчие от -градиционного Web-приложенил. Web-СервИСЫ XМL моЖно
ИСПОJlhзрватrь не T01IЬКO fЦЛSi того. 'Ч."Гобы возвращать 6рауэеру HТМL-кoд r: целью
визуа.цизации. Скорее наоборот, Web-еервис XМL чаще всего npедоoraшшет фym<
~ональf,[Ые воамОЖпосrn. анwrо.гичные возМХ)жностям стандартной библиотеКй
ПРОгpaмюibrO 1ЩЦа .NEТ ()iапример. специалъщте ВhJЧJJсJ;t;еНИЯ, выборку данных из
QataSet. чтение ценна акции и 1:,ц.).
1118 Чаt."Т~ V. W~Ь-ПРI1ЛОЖ1iН>ИЯ 1.1 WeJj-сер~ио.1:iI XМL
~мe. Web- серВIIIС XМL Мl&rщ.рff .NEТ npa~gSoдc:raeH~oro 'J'рnaня .оБCJtужтцtеroя {;epB~pOM
118 В' pc1f111Ka" ~ЩWlbt-lРГО !lирryалЬНОrti I(ffiQJJora. Однак.G" ICЗ.к П~SОfWIЛО~Ь В ГnBBe 23. с 'nОМtlЩblO
We'bD.e'l.'. WebServe.r ..е.&е в .NEТ 2 _О теnер.l;>МOЖI:Ю ззгруж~r" Wеь-сод~ржимоо н иэ lJО!ШJtь
:tlОn;:O . ~6rз (ПРИ разработке и ~еС'U1РОВШiIОII·
, Прмmм.ceнмe.NЕТ
liЗ,nnатформе
WlhЗ2
:=-.:: 8
'~Java {ИIJИ :NE:t}\.
т" "/"
НПР &XML
-зre~ ,
.. - .,
НПР&XМl.
Web~p "
нттр & XML
• (на :ЛIC~' nnaТфоpмlJ)"
1.
rJ!~ j!a 2~. Web-с;ервиObl XМL 1121
(ее обсуждение бу.дет цредлоЖ~О Цf.)З~) гeH~p»PYeт клиеит.cюm C:fI-хласс агента
на OCgOBe l'iМеющегося WSDL-ДОку!4ентц.
В более сложирух С:ЛУЧ~ (обы'ЦlО с Ц~ЬЮ гарантии совместимости) .при nо
С.троещш Web-сервиС'ов многие ;разработчики используют ПОДХОД, в рамках кото
рот:о сначала :вручную оцределлетсJ:'l WSDL-дqкумещ ПОСI<dIIЫty упомянутая выше
УТИJIМта КОМaидl'lОЙ СТРОI<И wsgl. ехе может генеРПР0Вать оnиса:нип интерфеШа.
AlUl Web-еерви~ XМL и на оснщ,е W5DL-сщредвтiения.
Транспортный протокол
Uoeдe создв,дия ПЩа агtЩТа Д1Щ "ВзЩ!Модействия с WеЪ-сер:висо-м XМL НlI.Иент
может выbJватl:! доступные -методы. l}<Щ уже подчерJЩВ-З:JIОСЪ, соответствующие
.дmщъre пеpt:дaIOТС,l'l с ПОМОЩЬЮ C~eВOГO црqтqкола J1f'IP. В частности, :и.ля оБМt:йа
информацией между потребитещши ~ WеЪ-Сервжт.m можно НClI.OЛЬЭGВатЬ НТТР
M~TOДbI GE·T и POST или ЭОАР.
в общем, ОСНGJВ:ньпrt варинитом выбора !!iбьrчно ОRазывается .SOAP, поскольку.
:как вы вскоре убедитесЬо. СQобщеНЩI SОЛР' могут содержать XML- ОIIйсания слож..
Hых ТИПОВ (ВЩ1]Ю:Чан ПОЛЬЗрЩ:lтeJ]Ъс,к;ие ТЦIIЫ: и типы из бибЛИQТек бшю:въrx классов
.NEТ), При ИСПОДЪ30В/:lНИИ hrrr-ПРОТЩWЛQвGЕТ и POST вам щщдетс:к OI'paНИчнтъся
более узким мвоществом Т1'Ц10~ XМL-cXeМ:ы.
Sys: t e rтi . Web. S:e:r:vices.Configu rat ion Содержит типы, ПОЗВО1ТЯющие ttастроить по
щщеМИ' 8 Web-сервиса XМL 8 ореде ВЫПQIIН,*,ИЯ
ASP.NEТ
З уэ tem .We b.se rv iсеЗ._Dе~ ~х ip~ ion Содержит 1илы' об6СЛEt4иваюЩие програММНОЕ!
взаимодейсtвие с WSDL-Аокум~нтам·, предлага
ЮЩИ~ ОПИ~НИ6 данногр Web- оервиса
Тип Описание
},
Замечание. В rщмка.х ttПР могут БЫТЬ ,ДQG1)'nIiЫМ~1 mлщ{() члеН!)I., имеющие атр~бут [W€bMethod].
Члены, не обозн~....енныв атрибутом [WеЬМеtl,(]Iщ1 J, не могут .В!>iзываТЬСI1 а1ентом МИ6Jна
ной строки Visua1 studio 2005 и выполните следующую IюманДУ. указав свободный
номер порта и физический путь к каталOlУ. содержащему ваш файл *. asmx .
WebDe v . We bSe r ver /port: 4000 /pa t h : " С: \ He ll oWor l dW e bSe r vi се "
После запуска Web-сервера откройте любой браузер и укажите в его окне имя
своего файла * _а smx , используя соот ветствующий номер порта .
Вам будет показан список всех Web -м еТОДQВ. доступных по этому адресу URL
(рис. 25.2).
HelloService
The follo wfГI g ope,"ations are supported . For d fo rmdl d еf iп i ti О П J plea se re'lI e w th e
S e rvice De s qJ.ptit!'t .
;'!.
< . ~ ;, ,
~ -_ .
Просмотр WSDL-документа
"Как уже упомщrалОСI!, WSDL двляется метаязыком, ОIIИс~ающцм шюгочдс
денныеособе}-I1-ЩСТИ Web-методов. дос'1ущiык по Да.Е!ЕР"муадресу URL. Обраггите.
DНИМЩ-1И(':uа ТО. что при npоверке Web-серв:исщ XМL .aвтOMaT]J~eclG1 гeJ;Iерируемая
страница теСтирОВaIЩЦ предлагает ССЫJЩУ Seгvice Dеsсгiрti оп (ОШJCэние сервиса).
В резулътате: щелчка на этой ссЬt1Ше к теКУЩеМу :аanросу :прис:оt;ди:н;яюrrсн СИМВОЛЫ
?-ws.d l. Когда среда БЬЩО,lJНеIЩЯ ASP.NJj;Т получает Зa:IJрОС ДJJ;Я Файл:'). • .аsЛ1~ с. та
ким принреnленIIblМ qффИШ:ОМ. ОН4 Е!:Бтома')'ически ВОЩJращает соответствующий
WSDL-код.. ошrnывающий. ца.ждый доступный Web-метоД.
Б настоящий МD1',ЩНТ ВЩ\IC не следует беспоROИТЬС~ о прирqде WSDL-Кi)Аа mm
формате WSDL-докумеита. Пока что важно ТОЛЪRО понимать, ЧТО WEjDL-ксщ onи
еьша~ то, кан Web-метоАbl MGryт ВЫЗЫБа'I1ьея с ПIi)МОЩЬЮ ИМеlОЩИХс,я: ПРОТШЮЛ(JS'
евяш WеЪ-сер1!иса XМL.
Автоматически генерируемаSl
страница т'естирования'
как вы TO:iIЪкa что убедились. работоспособность Web-сеРВИСQВ XМL МОЖНО про
верить с nОМОЩI:;Ю автомапмесЮl rehepJ-lруемой HTML-стршnщы n. браузере. Когда
обнаРУ.lКИВается l4ТГP-зanpос. указывающий на данный файл ". azUtx. среда ВЪПJОJl~
нения ASP.NEТ :использует фз:йл с именем Dеf.аUltW"Э cllНеlp.GеГJеr а tor . азрХ. чтобы
создатъ НГМL-стрafIИЦy. позволяюIЦYIO вызвать Web~MeTOAbl. доступные поданно
му URt. Этот файл * ..азр}\ можно найти в сmщующем 'ШlТaJJоге (З;1есЬ" щшеqно. блOR
<.версия> следУет заменить на номер вашей текущей версии . NEТ Fram.ework).
С: \ Windbws\.Mi CI'bsof t. NE'1' '. Framewor k\ <в-ерс:и:я> \CONFI G
<tit l~><%,*Servi сеЫате + ... " + GetLo c al i zect-rехt (j'W~'ЬSегvi се"" ' ) %><; / ti t J e~
на с,rщцующЦЙ.
Замечание. Как и в случае Web-узла ASP,NEr, файлы '*. sln проектов Web-сервисов XML, создан
ных в
Visual Studio 2005, размещаются в папке Мои документы\ Visual Studio 2005\
Projects.
rJ1ai3& 2:5, web-i:6рвиоы XML 1121
T~,
~l~ '~~."ll!,_~t!Пфl~
• мр,rю
Cr~&taI·Fl.S~, j
~""J ~~ , ."'3..1.t.~
. :.,\~ . •~~____~___ i! 1 ~-.
_'.•~.,__~_'_.~'~~_'~'.~ I
1Jsing ..1.~ystem:
using s.1~t;e-m. We,h.;
\»:sing Sp'tem. Web. serv:i..ce;;J ;
·I..lpin'i!! >SY5"t€!111. И'еЬ. $eI-:ч:Lcеs .:Р:rоt:о.еЩs;
['WcebS,eJ:-viсе (Ыа.m2s:рш::е =r'}Jt tp: / / temp.uri.@Ig{"T J
[WеhS~rVi.'СеВi.rrdil'н;r(с:.Щ-Ji't"rms';Г.Q
"" Ws;i.Рr0Цlе';з.ВавiоРrоНlеl 1) j
P1lbHc сlаs,з ~еr,,;i.О'е .~ E!y~t-el'\1, Web, Servi.ce~ •.WebServic:&
(
рдьНс ServiceJ)
{
1
( Wel1lo1e,t J"юd')
:p.lJblic string f)'el1owo:):,ld ()
{
:it!rt1,ll·f). :"Ней.о w.orld n ;
1128 Часть V, WеЬ·приложения и WеЬ·сервисы XML
[WebMethod]
public string TellFort\.Jne (string ЕопросПользователя)
(
string[] answers = ( "Будущее неоднозначно", "Да", "Нет",
"Вряд ли", "Спросите еще раз", "Определенно" 1:
11 Возвращение случайного оorзе'l'а на ВОnPОС.
Random r = new Random();
return string.Format("(O)? {l}",
вопросПользователя, answers[r.Next(answers.Length)]J;
..
...
Service
Click ft~:,rj'~ 'for !!I comp~ete list of opelratl0l15.
TellFortune
Test
То , ..st <ее "per.'lon u"ng th. нттр POST prota~ol, Qlick th. ·InVDk.' bUtton,
I !nvoke I
Таблица
. 25.3. OO'-lOв~,ые ч·nеНЫТl-1па S'v'$tе!J).W~Ь.
- Sег\!iсеs_ W·еЬSеrv iс е
Свойство Оn~саi-tие
l.'фр1iс.8't.i оп ОID!:J0.пеЧlIIвает доступ i'\ объекту Ht t 'pAppl iсаtiоиS t а'tе Mfi. Тf:!ft(УЩегёJ
НПР-заnрсса
Contaxt Об.еСfreчивае.т доступ 1( типу HttpContext , инкалСУJmРУlOЩ8МУ все НТТР-со
держимое . ИСnOflьэуемое Web-СерВ€рОМ ДМI НТТР-заriросов
Вы, возможно. )"!l{t' ПОНЯЛИ. ЧТО для построения Web-серв:и-са. способного осу
:щ~с:rщ:щть IIодцерзь.-Ry С'Боего СОСТОЛFlИЯ с ПОblОЩЬ'lО переменных Dpиложения и :се
анса [см . главу 24}. nbl должны Подучить СОQТВетсТВ'уЮЩНЙ ~Иn из WеЬ$ел' ice , по
СlЮ.lJЬнупоследдиЙ оnpe.делнет свgйм:ва App licat.ion и S~si.O'n. С др,Уг6Й стороны.
если II~! строите Web-сервис ЛМL. дЛЯ которото:не требуетсн ~ПОМНИ'lЪ" информа
ЦИI(j) о внешних ШЩЬЭЬватt>Л'n"Х.не требуется 'и расширение WebService_ МЫ снова
P~CCMOTP~ процесr- прстроеЩ'[f)' Web-сервиса XМL позже. в ходе нашего обtужде-
lЩЯ СВОЙ("I'ва Ел"й;> }еS",zsi О.h атрибута (WebMet.hod) .
1130 Часть У. Web-приложения и Web-сервисы XML
Атрибут [WebService]
Класс Web-сервиса XМL может быть помечен пеобязательным атрибутом
[WebService] (не путайте его с базовым классом WebService) . Этот атрибут под
держивает ряд именованных свойств, первым из которых является Namespace. Это
свойство можно использовать для указания пространства имен XМL. используемо
го в документе WSDL.
Вы. возможно, уже знаете. что пространства имен XМL используются для созда
ния контекста применения пользовательских XМL-элементов в рамках конкретной
груrшы (точно TaR же. как и пространства имен .NEТ). По умолчанию среда выпол
нения ASP.NEТ назначает для файла *. азrnх фиктивное пространство имен XМL
http://ternpuri.org. Аналогично по умолчанию Visual Studio 2005 назначает ДЛЯ
Narnespace значение http://ternpuri .org.
Предположим. что в Vlsual Studio 2005 вы создали новый проект WеЬ-сервиса
XМL с именем CalculatorService, определяющий следующие дна Web-метода с
именами Add() и Subtract().
Свойство Нате
llоc;uедиим йзр.асоматрl.ffiШ1:МЫХ здесь ~ОЙСТВ '1"Иtш WebS~rv i r;eA t,t,r i,bu t.e: i!В~
.ляe:I'СJI.ОВQЙСТВО Ndme, кот()рое: 'ИCIЮ:1IblIyetri'Ш,wllI укааamrя. нмеi-Щ Web-серllщ:а XMI"
ВИЛ1iIМOго nнеlIПD!lм nользоватеJU1м. 110,yьroлчанию 'ВНешнее ПМS!. Web-~I;epв:!il~ щек,
1'НЧНО имеН:И сюО':Г.ветс.ТВУЮЩffi'Q ·nша ЮL-"1:Сса lkOТf>pblbl. , в свОю Gчере~. 'ПО умщrча
НИlO тШЯе'!:сfi И:МН Servic~). Однако еСЛИВЫjЮтmе ~отдe:rtИть~ JIМjfl1t,'1~GGCj..NE'1' Р'!'
~оо'r»етС'ТЙУJOщего wsDl,...,иМени. вы M~e й3мевить a~ [W8b6.~r·vici'lJ 'J<!J(,
Jiau RОI{а~Ш1О tJИЖe.
(1
-.(1-
-
".'. __ ""
."U
. I ~~ '~ ..~
b::iJ 1&1, 'tJ:! ,
. _. -- -'-
{1_,,~ ..л...,"",~_~
> .....,. 1;..,: -.,....,...е
"".~ ~ ~-
...,.,. 0;, ."Ъ3 ~
~
-~-
~
,'a .
~
. !=
а;;1 "-I~'" •
I!д ~ :"".,~ 11f<" ~
I§I
fJ
Са IclJlatorV\febService
~: ' 1,
•!
. й~~~~<,;1~~;J~~.~~!&r;;~rf~"J~~М~J]",)~'J~~=-~:fi~r.~~r~~~i~~ ~j-J.W't7Jf
.~.,.
1132 Часть V. Web-nриложения и Web-сервисы XML
Атрибут [WebServiceBinding]
в .NEТ 2.0 Web-сервис XМL может содержать атрибут [WebServiceBinding].
Среди прочего этот атрибут используется для того. чтобы указать соответствие
данного Web-сервиса XМL " базовому профилю совместимости Web-сервисов (WSI)
версии 1.1". Но что это значит? Если вы активно работаете с Web-сервисамиXМL.
вы должны знать. что спецификации WSDL в процессе развития этой технологии
изменялись. Вследствие этого вполне обычной оказывается ситуация. когда один
и тот же элемент (или атрибут) WSDL имеет разные интерпретации в разных си
стемах разработки (ПS, WSAD), Web-серверах (IIS, АрасЬе) и архитектурах (.NEТ,
J2EE).
Очевидно. для Web-сервиса XМL это оказывается проблемой, поскольку одной
из задач разработки является упрощение способа обрабоТ1tи информации в меж
платформенном мультиархитектурном и многоязычном окружении. Чтобы решить
проблему. для ПОВЬШJения уровня межплатформенной совместимости Web-серви
сов организация WSI предлагает использовать открытыIe спецификации. В .NEТ 2.0
свойству ConformsTo атрибута [WebServiceBinding] можно назначить любое зна
чение из перечня WsiProfiles.
Замечание. Атрибут I rlеhJSеЛl'iсеВi !1dlщj] можно Т<tIОК1Э ИСМЛ6зОВать Для QпределеНИ,А пред
полагаемых qВЯЗ6Иконкреrнь.!х M61'OAOB по ЗН<I'IеНИЮGВРlI1ства Ыа те, Coot-веТСТElующие Г10Д
РlOБНос:ти МОЖhlО blаитИ в до~умеНl'аЩIlI\ ,NET Fram.e.work 2,0 SDK
Атрибут [WebMethod]
Атрибут .L WebM~etl"jod] ДQлжен указьшаться::для каЖДОГQ метода, :который .вы хо
тите Сдt'.J1ать досryпным в рамках данного Web-сер:виса XМL, как и большинство
ДР)'ГИХ атрибyroв. ТИП wеьм'еth':'dАttIiыiеe мФкет иметь це.1'lЬJЙ 'РЯJ'I; необяаатель
ных имеНОВaI-Пrьti СВОЙСТВ, Давайте рассмотрйм IULii'дУЮ из 'НмеЮ!цИхся здесь ВОЗ
мо1Ш-lOс-гей по оч:ереЩ1.
Боth Single Add(Single, Single) and Int32 Add(Int32, Int32) иsе the
message пате 'Add'. ИБе the MessageName property attribute to specify
unique о! the WebMethod cust ommessage патеs for the methods.
(Сообщение гласит: Single Лdd(Siпglе . Single) и Int32 Add(Int32. Int32) используют
одно и то же имя 'Лdd' для своих сообщений; используйте свойство MessageName
атрибута WebMethod. чтобы указать для этих методов уникальцые пользователь
ские имена сообщений.)
Здесь лучшим решением явдяется отказ от перегрузки метода Add ( ). Если же
перегрузка необходима. для устранения конфликтов имен в документах WSDL
можно использовать свойство MessageName атрибута [WebMethod].
public cla ss Service : Systero.Web.Services.webService -
{
(WebMethod (Descri pt ion = "Сложение чи с ел с плавающей точкой.",
ИеззаqeName = "AddFloats")]
publ ic float Add(float х, float у) { return х + у;
< /sc.ript>
<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0. 1 :4 242 4"
sqlConnectionstring="data sou.rce=127.0.0_1;Trusted_Connection=yes"
cook ieles s= "false"
timeout="20"
/>
• !
тип ВО8вращаемOl'О зна ЧСНЩj если ТW;:ОБое предУCJ\!Iо;rpено} :
Определение WSDL"документа
Действительный документ WSDL открывается и закрывается корневым эле
ментом <dеfiлitiолs>. В открывающем дескрипторе обьгпю определяются раз
личные атрибуты xmlns. Они задают пространства имен XМL, определяющие раз
личные подчиненные элементы. Как минимум. элемент <definitions> должен
указать пространство имен, где определены сами элементы WSDL (http://s c hema s.
xmlsoap.org /wsd 1). Для того чтобы быть полезным, открывающий дескриптор
<definitions> должен, кроме того, указать пространства имен XМL. определяю
щие простые типы данных WSDL, типы XML-схеМbl. элементы SOAP, а также це
левое пространство имен. Например. вот как выглядит раздел <definitions> для
нашего Web-сервиса калIiliYJlЯТора.
< /wsdl:dаfiпitiопs>
Элемент <types>
Сначада мы рассмотрим элемент <tУ'Р·еэ>. который <;:одержит О]]ИС'.анин.ВСf'Х
ТИПОВ данных. npедпarаемых Web-сервисом. ~ы. возможно, апаете. -что :я.зьш. XМL
сам определяет Рпд. ~ба:зо:вых" ТДI!ЮВ дaнн:.l:im(, И BC~ ою-r определены.в рамЮl'Х про
стра:нст:ва: .JIMeH XМL b.ttp~! !-w:w·w.W3.- DrЧ (,200] !XMLSGh~ma (которое доШЮiо бьtrъ
указаtiо n lюнте«сте Kop:t:teвoro элем:eJJТa <de:[ i n i ti ОЛВ ». Возъмем. например. ме
ТОД Sub1:ract _\} нашего Web-серВИса калъ-кyrщтора, ИlVlt>ющИЙ два входных параме
тра ЦeJJОЧНС.iК!itНОГО типа. В терминах W5DL тип SY$~e:rn .lnt32 среды СLП опИсы
вается в нонтенсте элемента ~сс rnрl ехТур.е:>.
<s:elernent паюе="StiЬti.асt">
<9 ;·comple.xType>
<s:sequence:>
<"$: el em-er1t тninOpcur::;="l" lTLaxOcc-UI5~"1" nалхе="х" t ype="s:int-" />
<s:eleHl\S:nt шi.nОс:сurэ=,11{\ rnaz'()ccUJrs=·'ll'f ni1l1n€="y" t:ype="s:i.nt" 1>
</ s : seglI€Tl,ce>
</S:С: Gmр.lех'Туре >
<:,'$: еl'€!щеl1t>
Элемент <message>
Элемент <message> используется для определения формата обмена эапросами
и ответами данного Web-метода. Поскольку один Web-сервис позволяет передачу
множества сообщений между отправителем и получателем , одномуWSDL-докумен
ту поэволяется определять множество элементов <mеээаче > , Кая правило. в этих
определениях используются тиuы' указанные в рамках элемента <t.ypes>.
Независимо от количества элементов <message >. определенных в докумен
те WSDL. они обычно "upисутствуют" парами. Первое определение представля
ет входной формат сообщения. а второе - выходной формат того же сообщения.
Например. метод Subtract () Web-сервиса CalculatorWebService определяет сле
дующие элементы <message> .
Замечание. Не все Web'MeToAbl требуют и запроса, и ответа. Если Web-метоА является "односто
ронним", для него необходим только элемент <ще.ssаgе> запроса . Обозначить Web-метоА,
как односторонний, можно с помощью атрибута [SOapDOCllmen tMethod] .
Элемент <portType>
Элемент <portType > определяет различные связи. которые могут возникать
между клиентом и сервером. и каждая такая связь представляется вложенным эле
Элемент <binding->
отот элемеl;IТ yJШзыва{'т точный формат обмена GET, POST И SОЛР. ЭТQ самый
··Jl.lliоrословНPIЙ~ И~ всех эле.менТОВ.• содержш:цихся в :КОНТексте lФрневоrо элемеата
<defini tion>. Вот, l-Janfщмер. ШIpeделеНйе ·9леме1-l11З. <Ьiлdiпg> с ОIШсщшем того.
KaJtвызьшающа:я: стороц_а МdЖет взаимодеЙствовать с Wеь'-меТQДОМ Myr-1et.h od ().
используя SQAR
Элемент <service>
Наконец. у нас есть элемент <service>. который указывает характеристИRИ
самого WеЬ-сервиса [например, его URL). Thавной задачей ЭТОl'о элемента являет
ся описание множества портов, открытых данным Web-сервером . Для этого эле
мент <services> может использовать любое число ВJюженных элементов <port>
(не путайте их с элементом <portType». Бот IЩК выглядит элемент <service> для
CalculatorWebService.
<wsdl:service name= "CalculatorWebService" >
<wsdl: documentation xmlns: ws,:il=''http://schemas .xmlaoap .org/wsdl/">
ЧУдесный Web-сервис хальКУnRтора
</wsdl:documentation>
<wsdl: po):-t name= "CalculatorWebServiceSoap"
bind_ing= ,. tns :CalculatorWebServiceSoap" >
< зоар : addres s 1. оса t i on="http; / / localhost: 1109/CalculatorWebService/
Service.asmx" 1>
</wsdl:port>
<wsdl:port name="CalculatorWebServiceSoap12"
binding=" tns : CalculatorWebServiceSoap12" >
<soap12:addr e ss location=
''http://localhost:ll09/CalculatorWebService/Service.asmx'' 1>
< /wsdl :port_>
</wsdl:se rvice >
Итак, как видите, WSDL-код, автоматически возвращаемый сервером IIS. не
является сверхсложным. но. поскольн:у WSDL представляет собой грамматику на
основе XМI" этот код достаточно "многословен". Тем не менее, теперь вы должны
лучше понимать роль WSDL. таи что давайте- рассмотрим немнOl'О подробнее про
токолы связи Web-сервисов XМL.
НТТР-мет(!д 'GБТ В режиме обмена БЕТ пара:метры дЬбавлпЮТGЯ к строке запроса дflНM9T';> URL
НПР-метад. POST В режиме обмена E'OST данные BCTP!1-иваЮТСR в ЗВГО1l0ВО~ HTTP-сообще.I'IИЯ.
а tie добавляются к отроке запроса
Перечни GET 11 POST поддерживают лередв"tу ТИГЮ6 3 ys t ero .EnUrn. .NEi. fЮ.CК.ОЛЬКУ
ЭТИ ТИni:/l лреДстаВ!1ЯIPТ<;:Я в .~идs стаТИ'iеских CТPOlli08bJX КОНОЩI1Т
Чтобы снова разрешить использование :НТГР-методов GET или POST для Web-
сервиса. добавьте имена HttpPost и HttpGet в соответствующий локальный файл
Web.config.
<configuration>
<system.web>
<webSerVLces>
<protocols>
<add name="HttpPost"l>
<add паше="НttрGet" />
</protocols>
</ webServices>
</system.web>
</configuration>
Снова напоминаем. что при использовании стандарТНЬLХ НТГР-методов GET и
POST У вас нет возможности строить Web-методы, допуснающие использование со
ставных типов (например, DataSet ADО.NЕТили пользовательский тип струнтуры)
в начестве параметров или возвращаемых значений. ДJIЯ простых Web-сервисов
это ограничение может быть ВПОJIне приемлемым. Одн<Шо при использовании свя
зи SOAP вы можете строить гораздо более совершенные Web-сервисы XМL.
Связь SOAP
Полный аналиэ возможностей SOAP выходит за рамни этого текста. однако сле
дует понимать, что SOAP нельзя назвать специальным протоколом. который может
использоваться наряду с другими существующими протокола.1\оШ Интернет (ИТГР.
Smp и др.). Общая задача SOAP. тем не менее, остается той же: обеспечить неза
висимый от языка и платформы механизм вызова методов, использующих состав
ные типы. Для этого SOAP преобразует каждый метод в сообщение SOAP.
Сообщение SOAP состоит из двух основных секций. Во-первых, есть конверт
SOAP. который можно понимать. к<ш абстрактный Rонтейнер для соответствую
щей информации. ВО-ВТОРЫХ. есть правила, которые используются для описания
информации в сообщении (размещаемой в теле сообщения SOAP). Необязательная
третья секция (заголовок SOAP) может использоваться для того. чтобы уназать об
щую информацию. насающуюся самого сообщения (например. информацию без
опасности или транз<шции).
Замечание. Флаг /server утилиты wsdl.exe в .NEТ 2.0 больше не используется. Теперь базо
вый программный код для сервера генерируется с помощью /serverlnterface.
ИСХОДItЫМ код. Файл :CarHlz."Object.. w.sdl размещен в подкаталоге, СОO'fВетотвvющ.ем Гf1эве 25.
ПреобразованиеWSDL-кода в лроrраммный
КОД агента ДЛЯ клиента
XOTil это и вежелателъuа. 110 .lЦIОJШ·е ВОЗМQ'ЖНО' построИТD базовыи протраминый
-:код :клиента, который будет вручнуоо от .кp~1ВaTЬ H1TP-а.'тединеВИе, СТРОИТЬ 50АР
сообщец;ия. вызыват.I'! Web-меroды И· В1illlОJЩЯ1'Ъ обратВfЮ трансляцию постynаю
щегоXМL-цотона:в 'Типы данны;х СТ$, Нац:ного более предпОЧТИТ.едrЬныМ подХодом
ОRазываетси чсполъзованме \·i,spl.e~e ДiJ1,Я генw-рирования класса агента, который
будет предстэ.ЭЛЯ'FЬ Web-методы. оцредеЛfП:шые данным фаШюм. .... asm:.:.
ДЛЯ 3Т1;>ГО ужrщите Скан МИНДМУN:J ИМЯ геRерируемorо' файла атента (с по
мощыо флаг·а i oU, t) И место рщзМ'~:ще:fJ.ИЯ WSDL- документа. По· умолчанию
wsdl"e:xe г-енерирует цporpа..1-vfМНЫЙ l-Ц1Д агента на Я3ЬJ::Юе Cit. Однтсо если вы Хо
тите иметь прогрaммный коц aTeнт~ ~Ш друто.м яэьmе .NE1: вы MO;fKeTe ИСПОЛЪ30-
Мть флаr /lёФgu.аgе.. СледУет ТaJЩtt' ::щать; что по умолчанию "Wsd.l.exe генерирует
llpoгpaмМlP>lii EQ)). агента, о'рeдnрлагающего ·связь (; удаленным Web-серВJiСОМ XМL
с IЮМОЩЬЮ SOAP. Чтсбы еоа;l'f..щный агент испЬЛЬЭовал НТI1?-Me-roд G.EJT ИЛИ .POST.
следует JRaa2.TP соответствующий протокол СВЯЗИ с помощью Ip:t at.D:col.
Другим важН:ЬfМ моме.том в отцqшеп= генерировав:йя програММНото пода
агента с ПОМОЩЬЮ w s d 1 . ехе явШI('ТСЯ ТО, ЧТО этё>му .инструме:wrу действите-лъно
требуется WSPL-доку.М!!Ю1l Web-t:.'ервдса :xмL. а не просто файл с :именем '*. asrnx .
С учетом этого следует понимать , "tfI'O если д.1JЯ разрооотни и. тестировa.ни.tI. We.b-
серш:tс-а вы щ; uользуете WebD$v,Web&e.rv er.E'xe, то· nеред ген.ерированием npo-
rpaммдorQ КОЩI агею'а ЩI'Я 1ЩИента .вы. сн:орее всего. захотите скопировать со.де.р
wsdl /out :pro x y . cs /n : Cal cula t orCl ien t h t tp : //loc a lhos t /C a l c Service/
Service .asmx?wsdl
Ca ncelAsync () Метод (новый в .NEТ 2.0), отменяющий асинхронный вызов метода Web-
сервиса XML, если вызов еще не завершен
<аррЗе t .t ihgs:>
<.add keY=" Gl!-lсurl" valu8'=' '' bttp·: I (Iocalb OBt /Са1 сSе'r viсе/Sелтiсе .21smx" />
<J'аррSеt tiпg-s>
<! солf ig:Urat.i Qn>
Хотя wsdl.exe все еще генерирует эти знакомые методы Begin/End. в .NEТ2 . 0
они считаются устаревшими, поскольку заменены новыми методами ХХХАs у пс () .
public void SubtractAsync (iпt х, int у)
(
this.SubtractAsync(x, у, null);
Новые методы XXXAsync () (как и связанный с ними метод CancelAsync ()) ра
ботают В паре с автоматически генерируемым вспомогательным методом (явля
ющимся перегруженной версией некоторого специального метода ХХХА s уп с ()),
который обрабатьmает аСИНХРОffi'iые операции, используя синтаксис событий С#.
Если рассмотреть программный код агента, вы увидите. что wsdl.exe генерирует
(ДЛЯ каждого Web-метода) пользовательский делегат, пользовательское событие и
полЬЗОВательский класс "event args", чтобы получить соответствующий результат.
st.aci.c
. \ IG)id W'S - S'Ubtr.асtСоm;::lеtе.d
- ·(оЬ 'i €-сt_ sелd.еr,~
SаЬtтасЕС'!:щурlЕ-tеQEvеntАrg:.>Е )
Обратите ЦН8:Мзrrnе нато. что новая логи]{8. aC~Iнxpoнвoro ВЫЗQlЩ D.NET 2.0
непосредствеliНО ОТО'Вражаетоо в ('..ннтаисис' событиЙ'С#, IЮ'rОРЫЙ. согласитщ:ь,
mшяется: более 8..fЩYpатпым:по сравнению с использо.ван:ием метс!Дов BeginxXX () I
.EJndJ;XX (), JЦfТl:'рфейса IAsYHcF_€ sulL, и делег.ата. AsyncCallbac'k.
3амечаНlfе. ДИВJJоговое OIQ-IQ Add' Web ReferenoE: не ПОЗВQIrяет ссыrrЗl'hСSI на Web-серв.ИОЫ XMl.
которые обслуживаются WabIJev. ~bSe rve .t. ехе.
1152 Часть V, Web-приложения и Web-сервисы XML
ф О" , ф 'Й' @) ~
URL: [Т - __ О • -" ~ -' . .. . - ,, , • • _. ~~_ • • • , c .• _'" ___ .. _ _ .. .. .___ ......~ ] ... Go
_ _ __ , _~_ "" ---,,_ ..;....~--'.:.. .. _~ ___. __ • _ _ __ .. _~·_ _oo3 ....
• ill2Q1 OjrectQr\'.
Que,y th. UDD! businos. '09lst,y ta F;nd "omp"Г1Ies ond p,aductlon Web
servic:es-.
• Iest MicrosQft уро, Oirectorll
Lont. t •• t W.b service. to use durinQ d.".lapment.
!
!
L _ ... _. ._ _ _ '- - - _ _ О~. - ' - . -_ _ - ••• ~ j
-
с.ncгi
using MyClientApp.localhosti
Замечание. В Visual Studio 2005 диалоговое окно Add Web Reference автоматически либо добав
ляет в проект новый файл арр. config. содержащий значения URL ссылок на Web-сервисы
XML, либо обновляет уже существующий,
1
Доступ к массивам
Со'здайте Web-мето.ц GetS alesT a.gLi nes () . .кОТQРЫЙ в()звращает М~СИВ строк.
предста:вшl,ЮЩИХ .данные текущих прод
аж раЗЛИЧIlliIХ щвтомобилей , и ме<год
S or t Са rMa ke s () . .котарый ПОЭВоЛИ'Г вызывщошей croPQHe
передать мэ:ссиg не
сортирФванных строк чтобы обратно получ:цтъ новЫ
Й массив отс-сртированных
строк.
, retu ~ a
( Vl e'bМ $ t h Cid
curD entD eals;
Доступ к структурам
Про1"01tОJ1 SOAP позволяет перt:дачу XML-преде'Fав.l1еннJ."j полъзо;вате:iIЬСКИ
Х ти
па}) данных {таких :как клаССЬ1 и структуры). WеЪ-
сервисы XМL ИС'llОЛЬЭУЮТТЩ1
Xro:1S eri аl iJ;!€r
ДJ'Щ 11реdбразованиитипа в XМL-иод (€M. главу
17, где имеется <$0-
лее подробная ИНфО{!!МсЩИЯ по ЭТОМУПОБоцуJ.
Нanом,н;и:м. что Xm1S eriali ze:r:
• Н'е выnо:лняет серИaJJ.Изацию прuват:щ,IX
данных: для сериапиЭац~m ИСПQJlЬЭУ·
Ю'1'СЯ ТОJ!J>ZФ OTКPЫТbl~ поля И евойства:;
// Пользовательский тип.
publi c struct SaleslnfoDetails
{
public string info;
public DateTime dateExpired;
public string Url;
<Salesl nfoDetails>
<iпfо> цены на Colt сниженьr на 50%!</info>
<dateExp ired>2004 -12-0 2 ТОО:ОО:ОО.000ОООО-06:00 </dаtеЕхpired>
<Url>http ://www. CarsRUs . com</Url>
</Sa1eslnfoDetails>
Исходный код. Файлы ПРl1мера СаrэSаleslnfоWS размещfЖЫ в Гlflдкэта/J'Оге.,· соответс.твующем главе 25,
A-D::Т:Оl"I'обl1Р.ьt1I=о:~ 'Web~ept,'l;J.1c
18 ~~~rl·r:ntlli.'''II'[J.t,:оry
Ъ.О"tтflЩ~Т ~11C'0K l'IaW\11<f fI}· ~:аfiлliju.hl !nw~!'!.t.i:H""1 fi-Mbl
..о..онны ;( Cors
~ G.clrS:.*.!.Jлf.rфl!t~
1~I-IЭАРI}5нь14' A'Of#I&tf"Go l"~r."ЩI1)" n'P-О,цlliК.а)(
• G.... tsatr-.I~
ПtmV"'t!tlие tteJ!iпе"'t1ы i (J"hJ1v~
,
111'
I _ , _ ,;; ..:_ _ """ _ ' ""i; =.=-
privat e void btnGetAI I Detai 1 5 Cli c k(ob ject sender, EventA rgs е)
(
SalesInfoDetails [ ] tbeSkinny = ws.GetSalesI n f .oDe t ai l s (i ;
foreach (SalesInfoDetails s in theSk in ny)
string d =
string. Format (" 1пЕо: (О) \nURL: (l) \nExpiratiOn Date: (2) " ,
5.1пЕо, s.Url, s.dateExpired);
MessageBox.Show(d, "Deta il s") ;
Colo, P.IN.m. ~
.. ~ - ;~'<, •...,. " ••._. ~ , --....::
-;-:"
6мый S"ake
; ~ОРИЧf1евый Zippy
, розовый ~ 8uddh. ~
_ ___. - ____ - -
_
-
,
_
,
О
~
Цоны на Coll сниж.ны на 507.1
B~ BMW KPМnIleJ<T~IOТC" 8,канаnьным '.~'OM
Подро6ноcrи
IC.~r~van бесплатно .. Cl1pocwтe ~ AlAnepal
I- ... . - :, ~-:-- =~ - --
get :trJ.is.dateEJ...-рirеtiF'iеld;
rE·tlJrl1
S€t thi$ .dat.eE xp.:i r e dF i~ld = val\l:e ; J
}
Замечание. СледУет панимать, что цеНтр тестИ!"ОВВIliИЯ является' не более чем центром тестиро
В8I'1Иfl. Не удивляиreСЬ,если БЫ обмаРУ*~1Те там множеС'fIЮ ~lещейств~тельныx ссылок. ПР14
запросе ПРQИЗ80,цСТВёhl~rых UDDI-серверов И")<i URL оказываюн:я горазд-о более ыа,цежными,
поеКОЛЫtу КОМПВliИЯМ оБЫЧI~О приходит-ся платиТЬ за 10, 'll'оБы Oltlji1 nриоyrСТ!lовали е соответ
ствующем спи оке.
Резюме
в ЭТОЙ главе Оbl.7Ш paccм:oTpeНhJ базОвые компоненты WеtyсервиСО.в и ОСFю.виые
этШIы ихпостроени,я в пределах штатформы .NEТ. lЛа:ва нач:инае't~я (' рассмотре
н:и;л пространств имен (и базовых тИIlОВ в этих ЛРОСТjJаЕСТВах имен), используемых
при СО3Дании wеhссервисО:в. Вы УЗВ8J1И. что До'1Я разработки WеЬ..()е~8иса в .NEТ
требуется .iIИШЬ яемнoлw большее. ~eM примене:ние атрибута rWe:bMetk10el] R: нвж
,дому члену. н:оторый вы хотите сделать доступным в рамках тшrа. преДСТавляю
щего дан:н:ы'й WеЪ.сервис XМL. Вы TaJtJRe можете (rЮ 'это необлззтелько) сделатъ
соот:ветствующиеТИIIl:iI' IJ}>ОИЗВDДНI:iIМИ от SуВtеrп.wеЬ.Sеrv ice:s _WelJ$,erv.1ce. ~IТO
бы (среди IIpочerоJ получить доступ RСВОЙСТВам Appllcation и Sessiol1. В СВJ1ЗИ
с о.сношrGЙ темО'Й обсуждения этой ГЛ8:вы БЪDШ таюке раССМfПРены три В3ЮJМ<iiс
IiН38HHыe ЮIЮчевые технологии - это механизм поиска (UDDJ)"язъш описания
(WSDL) ИnPОТfJКОЛЫ связи (GEI.. }'ОБI или 86АР).
После CD3Дa.Jl1m любого числа членов с атрибутами [WebMet.hod] вы :можете на
чать ВЗайМодейСl'Вие с. We1J-сервиtfJМ посреДствmvr промежуточноtо агента. Ттюй
агент может быть .сгеверирQВaН с :ПОМGЩЪЮ утилиты \VБ·dl.ехе. а сам аген1' может
испоЛЬзоваться клиентом подоб:во mобому друто:м:у типу С# , Аль'I"f'рнативG:Й ИШ.'ТРУ
менту командной стро:ки WSdl,8lte является испо.IIЬ30вание ViSLla] Studio 2005. :rдe
аналоi'ичные ВО3МОЖ1:ЮСТШ .предлагafjТ ДИaшirовое окно Add Web Referer)ce,
Предметный указатель
А J
ADO,929 JIТ-компилятор,57
ADO.NEТ, 929 Jitter.57
API,44
м
ARGB,820
MBR,708
ASP, 1022
МВR-объект,708
ATL,46
MBV.708
в МВV-объект,708
BCI,,43 МDI.753
МDI-Rонтейнер, 799
с MFC, 44
САО-объект, 711
CIL, 53; 599 о
СIL-инетрукция newobj, 251 ОТВ-тестер, 109
CLI,75
Р
CLR,48;65
РШ,538
CLS,48: 64
eode DOM, 642 5
СОМ, 45 50I,753
CТS,48 БОК 79
СШ,124 SOAP.1143
D т
DCOM,741 ТСР-канал, 706
DI5СО, 1120 TLS,539
DNA,46
DОМ,1017
u
UODI. 1120; 1158
Е URL активизации. 718
Еета International, 75
v
F VE5,75
FCL.43
w
G Web-пркпожение, 1010
GAC,72;471 Web-еервер, 1011
GDI+, 803 Web-сервие XМL, 1 117
GШ,124 Web-элемент управления, 1052
GUfD,471 WеЬЩ, 124
Windows Foгms, 751
н
WКО-объект, 711
HSB,820
WSOL, 1120; 1137
НТМL,1013
WSI.1122
НТМL-форма, 1014
НТГР. 1009 А
НТГР-запрое, 1043 Абсолютное имя, 71: 196: 444
НТГР-канал. 706 Абстрактный
НТГР-ответ, 1046 клаее.234
поставщик данных. 940
член. 212; 234
IDL,53
Автоприращение, 975
IIS, 746; 1011
Агент,1118
ILIDE#,611
прозрачный, 704
IРС-канал, 706
реальный, 705
Пред.м~тныЙ Уf(эзатель 1161
Адanхер ;/lщtных. 938; 969 синхронный. 572
ЛЮ11IlНыес~рnерные страниuы [А8Р). 1022 ВЫХОДНDЙ naрзметр, 144
Аионцмный метоД, 371
API-у'МС!iТ1Ф-МаЁдНОЙ СТРФRи. 117
r
I'aрНИТур'а Шрифта. 824
др-китен.тура 1~NЛ. 4~
Генерация объектов. 255
Асинх:рщшое у7.tалеЙНI)(;; БЗаЬ!\{{JдеЙстви.е. 748
Thнерирава1iИе и,с;:нлючениа. 2'7 7
.'\GЮIXpо.юiliIЙ
DJOбa11ЪiIblЙ
ВВОД-l;IЬШОД. 675
:КЭШ1Юм'поновочных. блОЯОВ
(GACJ. 72; 471
Вl.>IЭ.Q1'!" Q 70
yникaJ1bliЫЙ Щ1mтиф.инатор
(GU1DJ, 472
д9С1'.}'Р Н-ДЩIНЫМ. 968
Ipaфичосюш mпeрфейСll~ (GlЛ), 124
,'L'T'Qt-1арн!щ ошtрашLЯ. 567
IpyшIОВ'ое npеобраэование методов. 373
Атрцбут. 516
Ip)"rJповой
[Nlщ&tiЭJizеdJ,680
блОК-. .874
(ser1allZa.bleJ.6'7'8
ВlJlЭОВ. 354
!sync;h.mntzatloilj.593
[WebMelhod]. J 133 А
(WebSf'rV1cej, 1 LЭО Дaнm.l!"
(WebscrvlceBindingj. J 132 фоk!е. 1104
CIL.60l сщ~k!е. временные, 1! 05
ковте}>С'Тш,Щ. 556 cookJe. aepM!UJeIlIИble. 1105
ПОЛЬ30IЩ'J'e,I).ъскЩi.521 сооЮе. сеаноовые. ] 1'05
УРЩП-IЯ J{()МnОНОВ{Jчноrо б.WRа. 524 состояшrл npиложеНИЯ'. 1092
уровня модуля. 524 Сl'атичес~ие. 13'8
уровня ·~К3емnлsфа. 137
Б
ДвоичньiЙ код операдни CIL. 1302
БазОВЫЙ _КJlaCC. 211
Делегэ.'1', 62; 344; 568
о(,5общеШl'lll~ 434-
QооащеиныИ. 437
Бпб.!lИО'Тl;!rrа
Де.ilещроваиие.22'8
AТL,46
Демон. БВ5
MfC, 44
ДИЫlогово[> OIOiQ. 752: 9] 9
бilЭОIJЫХ K1Iar;-СоВ. 48
_модальное. 921
lЩвсе:ав.444
I10льзов;!\Те..i1ЬСХое. 919
npoг~",lМНoгo iЮда. 444
,ДинаМlftt~('RЩI
БiIOR
З'!-ГРУЗIЩ. 509
fiааllу.29З
памя:г.Ь. 121
iry/catrb.218
Дштамичееюш lWМnО1iОВQЧНЫЙ бmж.632
ЬДОfЩРQВНIl, 589
ДинамичеCi\0е C13SlэываННе. 513
БУМВ8.1l.ЫlOе lЮспрtm:,;веДeJ:-ше (':ТРФК. L85
В Д;lреит.uва
'Версии сеРI1!aJПИЗа1{ИИ, 697 ftde,fJi1e-. 41 1
Визуализация изображений, -840 #1f.410
!3ИР'1уальная СИ('7ема вьmОЛI-Ie1-Uffl (VES). 75 #reglon. 409
ClL. ВО)
~иР'''УaJIЫIЫЙ препроцесс-ора. 409
l{aTaJlClГ. 1011 ~IСЩ~'r",ер, 707
стек IlЫПолнеЕI~Л.. 603 )].иcnлеЙJ-JQе ИМJ{.
:511
Ч1Le.R. 172: 212 Домен ПРИJIОЖения. 549; 70]
в.тюжение ТIiШU13. 229 l;оад<iЩц;iИ ПО yNQ!JчаниЮ. 549
'вложенное пространство Кi,~(!.Н.lg,9 Десryn
ВнешнИЙ.код LЮДДер:;щ,,"" , 1 026 аСИZ~РО~IНЬdi.96в
ВliyrренниЙ тип дiurnых' 176 ROНky.pенfuыЙ. 586
Внух:peш-mя структура (;АС . 485 к арryмеmщ,! Еомюumой CТp01rn. 118
Временнысданнъrесооldе.11D5 Достулиостъ
ВспльТБаIOЩая DОДСRаЗlill. 885 ТИПОВ. ].30
ТkГJDоенНhIЙ "I'ИИ ДС!fЩЫХ CTS, ~2 члеНа!!,128
IlTO-РНЧllое И-СШПО'3eRИt". 291 ДочерниН
ВЫ90В ЩJасе.211
аcrшА,,]){}нБый570'' Мементyupав,ления, 797
1162 Предметный указатель
(kfa:u!t.428 мRoгoмoдyJlEныiii544
delegate. 344 общед;оступный, 471
dekle.l23 О.бщи:й:.714
iМ'лf.36.З· ощюмоДУш.ныЙ. 54: 44'9
eJ.1pliClt. 392 прИЩi'mыЙ', 464
n'''"'e.d , 407 conyrcтвуюЩИЙ •.44~
for.147 drатическИЙ., 632
'(OJ"e3clJ, 147 СТРОГО~Lченов~, 445
!Jnpl1c1t. 392 R,6нецлиmш,8ЗЗ
·lnterfare. 299 КOНRypf!НТI'IЫЙ ДQC'JYЛ. 586
iпtem.a] , 129 КанCOJ1bНЫЙ интерфейс ШllI&Эова1'еЛЯ {СЩ), 124
15.242 КОНШaFIта. 1.33
loCk.589 KOJl.C!l'JJYkТOp. 204
пamlЩрасе. 195 3а..ЦaнRый ШI УМОJIЧШIИlO, 12 {; 204
пёW. 120; 250 шmьзЬвaтf'.дьcRИЙ, 1,21: 204
oper<ltdr. 383; 393 ста'!ПЧесRИil·. 14 J
6fJ.t. НЗ Кoвтe.RC'I: 555
ФVеmdе. 2~)2 блt'.iКИРОшш. 589
рщЩщi , 14:~ GоадаваeмblЙlIЮ УМOJN<ЦnПO. &55
part:!al. 243 KOf.lTeh:ct.bo-независим:ьm ,ип. 555
pr:lvat e. ] 29 КОЕ,~RСТfЮ -CВJiзаН.ltllilЙ ТИП. 556
protecteo. 129; 225
protёcted illt.e mal129 .RJПOчеlЮе слово, 217
pulilic. 129 Мf:ню.780
reado111y. 13э M'Н"r.CRC'rН'Ыi1 атриб)l'li', 556'
rcl. 143 Контрнль ющца. Н)?4
.sl:aJecl. 227 Коор,цинмы
S'Шоf. 408 мировые. 8'l Б
эtасlmllос •. 406 при:борные. 81'5
statiG. 137 C"J'раничные, 815
tЫS.207 !Wnия [lOвеРЫJОСТНШI. ,З 19
tlщ:)w.277 Кореньцрилож~.253
l.1Ill.:heded ..400
цшщfе,402:
n
)Ща.ив:г no}'МОлчав.ию. 735
U5U1g, 70: 196;265
ЛОШU1Ънан uамяТБ ЩIТОна ('fL$), 539
'VirttIii] , 16912з 2
whеrе.4З2 М
w.hlle.148 Манифест. 53
)'ield.318 IЮМПЩiOВiiJ~!Ногоб]шit"d.. 449
fiOlnев:еuюе.217 УРО1ЩЯ ',\\,ЮДУЛ&. 450: 4'62
ИВОlD:\З..871 Маркер блокировки. 5'89
ВlJбираемая по умолчанию. 8&2 Марша.il}Пд 708
с· зависимой фиксацией. 873 ПО ЭlЩiЧени1О (МБVJ. 708
с н'езаБ'ИСИМОЙ ф'ИКС~)ДIiей, 873 по Gti'lJЛхе (MBR). 708
КоваРИa!fl'FlОСТЬ, 361 МаС:КИРЩ!Э.Юiое тенстоное !ЖНО. 869
Код операции CIL. 602; 6~ 1 М;;!ДЩЩ J,.в7
Itолле-ъ."цил обобщенная, 429 Н~ЫРОВ1fеИВhIЙ. 190
~i>IбинироваННDе'Оюш, 8/30 UРЖ>iоу['одьИЬ'IЙ, ! 89
Кdl\>mИЛJJТОР Me$ъIltJыool1e Ire'р~€crпgе ваеледозание. 460
CI1. 6О4 Меню,776
cS'C;. ехе , 80 tCQHTelOCТНoe.180
J1авЮ . ехе. 604 Meтai\aн1J:Ыe.53
опера.:rивЯЫЙ.448 /(ОМIlQ1ЮВОЧ!10г0 блt>:ка. 449
l{.dМПИЛJЩШl у~ная. 4J (.) тшщ.496
~oМnOHeнT. 752 Метка K(JДa. БО']
КОМll Оl'lовоч r:IЫЙ БЛОN. 50: 443 Метод.2Р3
диваМК'lее/шЙ. 632. g~t. 215
1164 Предметный указатель
МainО·116 Общий
set,215 компоновочный БЛОI(, 714
анонимный. 371 11ромежyroчный язык (СЩ, 53; 599
обобщенный, 424 ОбъеRТ, 120
статический, 137 номанды, 937; 959
Мировые координаты , 815 одиночного вызова , 712
Мнемоника CIL, 602 предусматривающий освобождение
Мнемоническая клавиша, 865 ресурсов, 263
Многодокументный интерфейс (МШ), 753 предусматривающий финализaциIO . 260
Мноroмодульный }(Омпоновочный блок. 54 соединения, 936
Модальное диалоговое окно, 921 сообщения. 704
Модель транзакции, 937
ЛDО.929 чтения данных, 939; 957
code ПОМ, 642 Объектная модель документов (DОМ), 1018
СОМ, 45 Объектныйграф, 253;679
локализации/делегирования, 228 Объекты поставщика данных ADO.NEТ, 931
ОДНО модульной страницы, 1026 Ограничение
страницы с внешним кодомподдержки. 1032 атрибута,523
Модификатор обобщения, 430
partial.243 Однодокументный интерфейс (8Ш), 753
доступности, 128 Одно модульный компоновочный блок, 54;
параметра, 143 449
Модуль, 54; 449 Окно
первичный , 54; 449 диалоговое, 919
Мониторинт файлов. 673 комбинированное, 880
модальное, 921
Н
отмечаемого списка. 877
Надпись . 865 с nисJtа,879
Наследование. 211 Оперативный компилятор , 448
конфиrypаuии,1115
Оператор
перекрестное,460
if/else, 149
форм , 921 swltch,150
Невыровненный массив. 190 Операuии со строками, 183
Необработанное исключение. 295 Операция
Несвязный уровен:ь ADO.NEТ. 969 &.404
Неуправляемые ресурсы , 260
".404
Не.явноеприведение типов. 241
+=.354
о =.355
Область клиента формы, 811 >,406
Обобщение. 413 ? ? 194
Обобщенная атомарная, 567
коллеКЦИЛ,429 восстановления иа объектного образа, 161
структура, 426 разыменования указателя, 406
Обобщенный создания объектного образа, 160
базовый класс. 434 Ответный файл, 86
делегат. 437 Открытый
метод. 424 интерфейс класса, 209
свободный тип. 431 ключ.,472
Обработка Отладчик cordbg.exe. 87
исключения. 278 Отложенная подци:сь, 476
множества исключений. 288 Отношение
Общая система типов (CТS), 48 локализации, 222
Общедоступный компоновочный блок , 471 подчиненности, 222
Обще.языковая Отобрcuнение, 501
инфраструктура (CLI), 75 Очередь финализации, 263
среда выполнения (CLR). 48 Ошибка
Общеязыковые спецификации (CLS), 48; 64 пользовательская. 271
программная.271
Пре.дМЕ\ЛIЫЙ укsдатель 1165
n Предста Rлешre. 989
Jla:p.3.Мe'rP J1pеооравовзиис:
I'J:Ы:ШJ,/Щ oiii. 144 неЯRНiое.300
""- ......-"'"
"" I6ТU"bIfJtlIl
IЮСУТИ, еще рукоrшсью. При ;)ТОМ I IСЛЬ..'IJI скаЗ<I:rъ. 'по ' lepftblC
Ш!а излаtmя КПИНi был.и uсуда'flIЫМИ - в катеГОРИJI КIIИ-Г
по програ.мМIJроваmпu книга I3bl,дВJlгалась на 11000УЧСIJИ('
fXI4f".NПD I ~ Щ>СМlшJoIt Л\\'ard в 2002 I'ООу, а в 2003 ''ОД}' ей БЫJlа IlРИСJЮСIli\
ЪeafleJlErU,. .tad прсмия Rct('l"('ncC\\'arc Ехссll"лсс A\\-·ard. Но. участвуя [:осле
Afla' dм~ ЭТОЮ в pa3p.tOOткe общ"языкOIЮЙ С[1Сды 1II,ПТОJ[D('I:ШЯ (CLR),
Я CMOI' npLliiTJ1. к 6олсt:' l"Лу60кому IЮIПlМi\lШ.ю ВU3МОЖlJостей
DIICOIII"".913.0
'" "~""'" ПJш'fформ:ы .NET 1I тонкостеА языка п рограмми роваЮIS\. С#,
и ТВlcpb мо.гу 3аЮlитЬ, 'ттотреТЬС ИЗДВIIне ;JToii КIШГН Ile менее
полно. чем МОII ,",наш'я в .}тоЙ oful acтlt.
Если 8Ы Чl1ТilJII1 r: (Х"дыдущие 1Iз,даН1I,н I<IJИrn, пам буд<'Т "РИЯТII.о
УЗ llаТl" 'Jтo u TPCTI,C издание доб.ШЛСfЮ IlCCKOJlbKO нопых ГJlап.
К,юме ТОГО, ТСК('Т глав, J1ОСlJЯЩCJШЫХ 1"'P<"IMIoI<lТlIIte 06щero
Pd3 . . ._ ... · • промежутоЧJЮro я:н:.гка (С I L), о(юбщеuШI.М .NET и сервисам
. . . . . . ~IIO •• _ _
сср"аJШЗJЩIIИ объектон был ПОЛlfOС'fЬЮ нерсрабornl1 с У'I"t"Гом
-.=:$ &$1." ......
IIODЫ); IJОЗМОЖIIОt:теЙ. п редлагаемых платформо.Й ,NET 2.0 (YrO,
2 qм.......
••.., "* 5 СО: "QiFI
на п ри мер. 'ЛШ Ы, допускаЮIШlе зtlачеllИС " uH, коварИ',шпю..;ть
nCJICraтoD, шаблон ы страJlИЦ ЛSР .NET 2.0 11 »оные злем~пты
управления Wiooo\\'!'j Fопш. IJCOO1H,,'JYCMblt:' ДЛЯ созданиS\.
• • iJ '1 r.lК Ra;jhlВИемых 'СЧХ)I( СОСТОЯНИЯ· ).
n., г
---
о; р . ,..
'''_.3 I
.... . . .
yr
.. np ... , . а
:
l$ 3I
::;11',,,,, 1$!1.1
для СПСЩJалuсто,П 8 областн разработки програ ммноro
обеСIlСЧСIIIНI и студеитоо старших KypcOtl, IIзучающих
и..нформати ку. Поэтому 111" СJlеДУСТОЖJщать, '11'0 в не.!
"ССКОДЫ(О ГЛdВ будет ПО"DЯЩCJЮ IЩ"К.lШ.М н КOHCТP)'l(ЦIJSl.M
УСЛО8ВО/'О Щ'р('};ода. Нitшсй цел ью Я1lJlН{"f{'Я "оздание н адежной
базы для п рограММНPUВaJ-JИЯ на языкс С# 11 ПОlШМ<J,II.ИС
ОСНОНIfЫ:Х ЗJ1емеllТОВ 11 ВО3МОЖllOстсilШJilтформъь . NЕТ
(сборок, удалеШlOfО roаимодейсТ8НЯ, windows Forms, Web
Foгrns. АОО .NEТ, wсь..служБ ХМL IIT.II,). Освш:.н материал.
[)реДСТa.вJJсШ:tl,ш в 25 ГJlil вахзroй КIШГИ, вы СМОЖt'ТС
щmменить НОЛУЧСIIН Ы(' :шаllИЯ Б той конкретной области
WWW\' .SI 3 !1PA=~ u роrраммироnания, в котороН работаете 11101.)1 самостоятельно
rl fЮдOJlЖ ИТЬ да 'D>IIСЙШсе исследова.н ~IС IICWt:ЧСРl1асмы х
c.2005.
''''''1
.".-~
~
.. --
NП"l-t.
. " .ot'p .,
_ _ __
• '".... , _ ..
_ " . , ..... ~f\>Co!IO_"Vin;:o..r
_ . faroa. ",,,,·r M . '""
Ученье - свет, анеученье - тьма
ШlpoдшIlI МУДРОСТЬ.
библиотека
форум
каталог