Г. Шилдт - С#4.0 Полное руководство (1160795), страница 97
Текст из файла (страница 97)
Такая архитектура вполне пригодна для обработки событий средствами СФ, поскольку дает возможность создавать обработчики событий для реагирования на различные сообщения и затем просто вызывать обработчик при получении конкретного сообщения. Так, щелчок левой кнопкой мыши может быть связан с событием ьецггопс11сх. При получении сообщения о щелчке левой кнопкой мыши вызывается метод ОпьицбсопС11ск (), и об этом событии уведомляются все зарегистрированные обработчики. Разработка программ для Х(пг(оьчя, демонстрирующих такой подход, выходит за рамки этой главы, тем не менее, рассмотрим пример, дающий представление о принципе, по которому действует данный подход.
В приведенной ниже программе создается обработчик событий, связанных с нажатием клавиш. Всякий раз, когда на клавиатуре нажимается клавиша, запускается событие кеургевв при вызове метода опкеургезв (). Следует заметить, что в этой программе формируются А)ЕТ- совместимые события и что их обработчики предоставляются в лямбда-выражениях. Пример обработки событий, связанных с нажатием клавиш на клавиатуре. цавпд яувгев; Создать класс, производный от класса Ечепслгдв и храняший символ нажатой клавиши. 510 Часть (. Язык С№ с1аяя КеуЕчепГАгдя : Ечепсйгдя ( рпЫ1с спал сЫ ) // Обьявить класс события, связанного с нажатием клавиш на клавиатуре. с1аяя Кеукчепс ( рпЫ1с ечепс Ечепонапб1ег <Кеуачептйгдя> Кеургевя/ // Этот метод вызывается при нажатии клавиши.
рпЫ1с чога ОпКеургеяя(сваг )геу) ( КеуЕчепсйгдя )г = пен Кеувчептйгдя()г 1г(кеургеяя != пп11) ( )г.сп = Кеу) КеуРгеяз (тЫя, К) ) ) ) ) // Продемонстрировать обработку события типа КеуЕчепс. с1азя Кеукчепяоешо ( ятас1с чо1г( Маги() ( КеуЕчепг Кечс = пеи КеуЕчепя()) Сопяо1екеутпго )геуг зпс сопят = О) // Использовать лямбда-выражение для подсчета нажатых клавиш. КечЫКеуРгеяя += (яепбег, е) > сопля++) // сопля — это внешняя переменная Сопяо1е.иг1теь1пе("Введите несколько символов. " + "По завершении введите точку."); бо ( кеу = Сопво1е.неабКеу(); КечмбпКеургеяя(йеу.КеуСЬаг); ) иЫ1е()сеу.кеусйаг (= '.'); Сопяо1е.игьсеЬзпе("Было нажато " + сопля + " клавиш."); Вот, например, к какому результату приводит выполнение этой программы.
Введите несколько символов. По Получено сообщение о нажатии е Получено сообщение о нажатии в Получено сообщение о нажатии Получено сообщение о нажатии Получено сообщение о нажатии Было нажато 5 клавиш. завершении введите точку. клавиши: клавиши: е клавиши: я клавиши: клавиши: // Использовать лямбда-выражение для отображения факта нажатия клавиши. Ьечм КеуРгеяя += (яепдег, е) => Сопяо1е.иг1ге11пе(" Получено сообщение о нажатии клавиши: " + е.сЫ г Глава 15.
Делегаты, события и лямбда-выражения 511 В самом начале этой программы объявляется класс КеуЕчепгдгцз, производный от класса ечепсдгцз и служащий для передачи сообщения о нажатии клавиши обработчику событий. Затем объявляется обобщенный делегат Ечепснапд1ег, определяющий обработчик событий, связанных с нажатием клавиш. Эти события инкапсулируются в классе Ке уЕчепг, где определяется событие Кеурге за. В методе Мадп () сначала создается объект )гечс класса КеуЕчепт.
Затем в цепочку событий )сенс. Кеургезз добавляется обработчик, предоставляемый лямбдавыражением. В этом обработчике отображается факт каждого нажатия клавиши, как показано ниже. Кечг.кеуРгезз += (яепдег, е) => Сопзоге.нгтгеььпе(" Получено сообщение о нажатии клавиши: " т е.сл) Далее в цепочку собьпий )гечс. Кеургезз добавляется еще один обработчик, предоставляемый лямбда-выражением. В этом обработчике подсчитывается количество нажатых клавиш, как показано ниже.
Кечс.Кеуртеяз += (яепдег, е) => соопс++т О соипс — это внешняя переменная Обратите внимание на то, что сорос является локальной переменной, объявленной в методе Мадп () и инициализированной нулевым значением. Далее начинает выполняться цикл, в котором метод )сенс. Опкеургезз О вызывается при нажатии клавиши.
Об этом событии уведомляются все зарегистрированные обработчики событий. По окончании цикла отображается количество нажатых клавиш. Несмотря на всю свою простоту, данный пример наглядно демонстрирует саму суть обработки событий средствами С(). Аналогичный подход может быть использован и для обработки других событий. Безусловно, в некоторых случаях анонимные обработчики событий могут оказаться непригодными, и тогда придется внедрить именованные методы. 514 Часть (.
Язык С(г ияьпэ Зуяиев) обычно вводится в самом начале любой программы на С)). Как пояснялось в главе 14, классы ввода-вывода определены в пространстве имен Зуягев. 10, подчиненном пространству имен Буя Сев. Ему подчинены и многие другие пространства имен, относящиеся к разным частям библиотеки классов С(). Пространства имен важны потому, что за последние годы в программировании "расплодились" в огромном количестве имена переменных, методов, свойств и классов, применяемых в библиотечных программах, стороннем и собственном коде. Поэтому без отдельных пространств все эти имена будут соперничать за место в глобальном пространстве имен, порождая конфликтные ситуации.
Так, если в программе определен класс Г1ис(ег, то этот класс может вступить в конфликт с другим классом р1пбег, доступным в сторонней библиотеке, используемой в этой программе. К счастью, подобного конфликта можно избежать, используя отдельные пространства имен, ограничивающие область видимости объявленных в них имен. Объявление пространства имен Пространство имен объявляется с помощью ключевого слова иавеярасе. Ниже приведена общая форма объявления пространства имен: павеярасе имя ( члены где имя обозначает конкретное имя объявляемого пространства имен. При объявлении пространства имен определяется область его действия. Все, что объявляется непосредственно в этом пространстве, оказывается в пределах его области действия.
В пространстве имен можно объявить классы, структуры, делегаты, перечисления, интерфейсы или другие пространства имен. Ниже приведен пример объявления павеярасе для создания пространства имен Сопите г. В этом пространстве локализуется имя, используемое для реализации простого класса вычитающего счетчика СоипСРоии.
// Объявить пространство имен Пля счетчиков. павеярасе Соипгег ( // Простой яычитаюший счетчик. с1аяя Соипсоонп ( 1пс ча1; риЬ11с Соиппоонп(ьпи п) ( ча1 = и; ) риб11с чо1б йеяег(1пс п) ( ча1 = п; ) рио11с ьпс Сония() ( 11(чя1 > 0) теоигп ча1--; е1яе гесигп 0; ) Глава 16. Пространства имен, препроцессор и сборки 515 ) Это конец пространства имен Соппгег. Обратите внимание на то, что класс Соцптпомп объявляется в пределах области действия пространства имен СоцпСег. Для того чтобы проработать этот пример на практике, поместите приведенный выше код в файл Соцп ге г. Ся.
Ниже приведен пример программы, демонстрирующий применение пространства имен Соцптег. Продемонстрировать применение пространства имен Соцпсег. цяьп9 Яуясепн с1аяв Нзоещо ( ятагьс тога мвтп() ( Обратите внимание на то, как класс Соцпяоонп // определяется с помощью пространства имен Соцпяег.
соцпсег.соцпсоонп сб1 = пен соцпсег.соцпсоонп(10)т ьпс 1; бо ( ь = сб1.Сопля()) Сопяо1е.игкпе(1 + " ")т ) нл>1е(х > 0); Сопво1е.Хг1геьвпе()т // Кще рая обратите внимание на то, как класс Соцпгоанп определяется с помощью пространства имен Сацпгет. Соцпьег.соцппоонп сб2 = пем Соцпьег.Соцпсоонп(20)т бо ( 1 = сб2.Соцпс()т сопво1е.хгт.ке(1 + " ")т ) нв11е(1 > 0)) Сопяо1е.иггяеьтпе()т сб2.пенес(4)т с(о ( 1 = сб2.Сопля()т Сопяо1е.иг1ге(1 + " ")т ) нв11е (1 > 0) ) сопяо1е.хлгсеьапе()т ) ) При выполнении этой программы получается следующий результат. 10 9 8 7 6 5 4 3 2 1 0 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 4 3 2 1 О Для того чтобы скомпилировать эту программу, вы должны включить приведенный выше код в отдельный файл и указать его вместе с упоминавшимся выше файлом, содержащим код объявления пространства имен Соцпсег.
Если этот код 516 Часть!. язык С() находится в файле Но()еще. ов, а код объявления пространства имен Соппгег — в файле соппсег. св, то для компиляции программы используется следующая командная строка. свс Маэеяс.св ссвпсев.св Некоторые важные аспекты данной программы заслуживают более пристального внимания. Во-первых, при создании объекта класса СоппСГ)онп необходимо дополнительно определить его имя с помощью пространства имен Соппгег, как показано ниже. Ведь класс Сопок()омп объявлен в пространстве имен Соппгег.
Соппоег.соопппонп оо1 = пен Соопоег.соопгпонп(10) Это правило можно обобщить: всякий раз, когда используется член пространства имен, его имя необходимо дополнительно определить с помощьк) этого пространства имен. В противном случае член пространства имен не будет обнаружен компилятором. Во-вторых, как только объект типа соппсег будет создан, дополнительно определять его члены с помощью пространства имен уже не придето(. Следовательно, метод сс(1. сопл с () может быть вызван непосредственно без дополнительного указания пространства имен, как в приведенной ниже строке кода.
1 = ог(1.Попас() ' И в-третьих, ради наглядности примера рассматриваемая здесь программа была разделена на два отдельных файла. В одном файле содержится код объявления пространства имен Соипгег, а в другом — код самой программы )(ПГ)ело. Но оба фрагмента кода можно было бы объединить в единый файл. Более того, в одном файле исходного кода может содержаться два или более пространства имен со своими собственными областями объявлений. Когда оканчивается действие внутреннего пространства имен, возобновляется действие внешнего пространства имен — в примере с соппсе г это глобальное пространство имен. Ради большей ясности в последующих примерах все пространства имен, требующиеся в программе, будут представлены в одном и том же файле.
Следует, однако, иметь в виду, что их допускается распределять по отдельным файлам, что практикуется чаще в выходном коде. Предотвращение кон(рликтов имен с помощью пространств имен Главное преимущество пространств имен заключается в том, что объявленные в них имена не вступают в конфликт с именами, объявленными за их пределами. Например, в приведенной ниже программе определяются два пространства имен.