C# 4.0 полное руководство - 2011 - Герберт Шилдт
Шрифт:
Интервал:
Закладка:
public void OnSomeEvent() {
if(SomeEvent != null)
SomeEvent(this, EventArgs.Empty);
}
}
class EventDemo7 {
static void handler(object source, EventArgs arg) {
Console.WriteLine("Произошло событие");
Console.WriteLine("Источник: " + source);
}
static void Main() {
MyEvent evt = new MyEvent();
// Добавить обработчик Handler() в цепочку событий, evt.SomeEvent += Handler;
// Запустить событие, evt.OnSomeEvent() ;
}
}
В данном примере параметр типа EventArgs не используется, поэтому в качестве этого параметра передается объект-заполнитель EventArgs . Empty. Результат выполнения кода из данного примера следующий.
Произошло событие Источник: MyEvent
Практический пример обработки событий
События нередко применяются в таких ориентированных на обмен сообщениями средах, как Windows. В подобной среде программа просто ожидает до тех пор, пока не будет получено конкретное сообщение, а затем она предпринимает соответствующее действие. Такая архитектура вполне пригодна для обработки событий средствами С#, поскольку дает возможность создавать обработчики событий для реагирования на различные сообщения и затем просто вызывать обработчик при получении конкретного сообщения. Так, щелчок левой кнопкой мыши может быть связан с событием LButtonClick. При получении сообщения о щелчке левой кнопкой мыши вызывается метод OnLButtonClick (), и об этом событии уведомляются все зарегистрированные обработчики.
Разработка программ для Windows, демонстрирующих такой подход, выходит за рамки этой главы, тем не менее, рассмотрим пример, дающий представление о принципе, по которому действует данный подход. В приведенной ниже программе создается обработчик событий, связанных с нажатием клавиш. Всякий раз, когда на клавиатуре нажимается клавиша, запускается событие KeyPress при вызове метода OnKeyPress (). Следует заметить, что в этой программе формируются .NET-совместимые события и что их обработчики предоставляются в лямбда-выражениях.
// Пример обработки событий, связанных с нажатием клавиш на клавиатуре, using System;
// Создать класс, производный от класса EventArgs и // хранящий символ нажатой клавиши.
class KeyEventArgs : EventArgs { public char ch;
}
// Объявить класс события, связанного с нажатием клавиш на клавиатуре, class KeyEvent {
public event EventHandler <KeyEventArgs> KeyPress;
// Этот метод вызывается при нажатии клавиши, public void OnKeyPress(char key) {
KeyEventArgs k = new KeyEventArgs();
if(KeyPress != null) { k.ch = key;
KeyPress(this, k) ;
}
}
}
// Продемонстрировать обработку события типа KeyEvent. class KeyEventDemo { static void Main() {
KeyEvent kevt = new KeyEvent();
ConsoleKeylnfo key; int count = 0;
// Использовать лямбда-выражение для отображения факта нажатия клавиши, kevt.KeyPress += (sender, е) =>
Console.WriteLine(" Получено сообщение о нажатии клавиши: " + e.ch);
// Использовать лямбда-выражение для подсчета нажатых клавиш.
kevt.KeyPress += (sender, е) =>
count++; // count — это внешняя переменная
Console.WriteLine("Введите несколько символов. " +
"По завершении введите точку.");
do {
key = Console.ReadKey(); kevt.OnKeyPress(key.KeyChar);
} while(key.KeyChar != '.');
Console.WriteLine("Было нажато " + count + " клавиш.");
}
}
Вот, например, к какому результату приводит выполнение этой программы.
Было нажато 5 клавиш.
В самом начале этой программы объявляется класс KeyEventArgs, производный от класса EventArgs и служащий для передачи сообщения о нажатии клавиши обработчику событий. Затем объявляется обобщенный делегат EventHandler, определяющий обработчик событий, связанных с нажатием клавиш. Эти события инкапсулируются в классе KeyEvent, где определяется событие KeyPress.
В методе Main () сначала создается объект kevt класса KeyEvent. Затем в цепочку событий kevt. KeyPress добавляется обработчик, предоставляемый лямбда-выражением. В этом обработчике отображается факт каждого нажатия клавиши, как показано ниже.
kevt.KeyPress += (sender, е) =>
Console.WriteLine(" Получено сообщение о нажатии клавиши: " + e.ch);
Далее в цепочку событий kevt .KeyPress добавляется еще один обработчик, предоставляемый лямбда-выражением. В этом обработчике подсчитывается количество нажатых клавиш, как показано ниже.
kevt.KeyPress += (sender, е) =>
count++; // count — это внешняя переменная
Обратите внимание на то, что count является локальной переменной, объявленной в методе Main () и инициализированной нулевым значением.
Далее начинает выполняться цикл, в котором метод kevt. OnKeyPress () вызывается при нажатии клавиши. Об этом событии уведомляются все зарегистрированные обработчики событий. По окончании цикла отображается количество нажатых клавиш. Несмотря на всю свою простоту, данный пример наглядно демонстрирует саму суть обработки событий средствами С#. Аналогичный подход может быть использован и для обработки других событий. Безусловно, в некоторых случаях анонимные обработчики событий могут оказаться непригодными, и тогда придется внедрить именованные методы.
ГЛАВА 16 Пространства имен, препроцессор и сборки
В этой главе речь пойдет о трех средствах С#, позволяющих улучшить организованность и доступность программы. Этими средствами являются пространства имен, препроцессор и сборки.
Пространства имен
О пространстве имен уже вкратце упоминалось в главе 2 в связи с тем, что это основополагающее понятие для С#. В действительности пространство имен в той или иной степени используется в каждой программе на С#. Потребность в подробном рассмотрении пространств имен не возникала до сих пор потому, что для каждой программы на C# автоматически предоставляется используемое по умолчанию глобальное пространство имен. Следовательно, в примерах программ, представленных в предыдущих главах, использовалось глобальное пространство имен. Но во многих реальных программах приходится создавать собственные пространства имен или же организовать взаимодействие с другими пространствами имен. Подобные пространства будут представлены далее во всех подробностях.
Пространство имен определяет область объявлений, в которой допускается хранить одно множество имен отдельно от другого. По существу, имена, объявленные в одном пространстве имен, не будут вступать в конфликт с аналогичными именами, объявленными в другой области. Так, в библиотеке классов для среды .NET Framework, которая одновременно является библиотекой классов С#, используется пространство имен System. Именно поэтому строка кода
using System;
обычно вводится в самом начале любой программы на С#. Как пояснялось в главе 14, классы ввода-вывода определены в пространстве имен System. 10, подчиненном пространству имен System. Ему подчинены и многие другие пространства имен, относящиеся к разным частям библиотеки классов С#.
Пространства имен важны потому, что за последние годы в программировании "расплодились" в огромном количестве имена переменных, методов, свойств и классов, применяемых в библиотечных программах, стороннем и собственном коде. Поэтому без отдельных пространств все эти имена будут соперничать за место в глобальном пространстве имен, порождая конфликтные ситуации. Так, если в программе определен класс Finder, то этот класс может вступить в конфликт с другим классом Finder, доступным в сторонней библиотеке, используемой в этой программе. К счастью, подобного конфликта можно избежать, используя отдельные пространства имен, ограничивающие область видимости объявленных в них имен.
Объявление пространства имен
Пространство имен объявляется с помощью ключевого слова namespace. Ниже приведена общая форма объявления пространства имен:
namespace имя {
11 члены
}
где имя обозначает конкретное имя объявляемого пространства имен. При объявлении пространства имен определяется область его действия. Все, что объявляется непосредственно в этом пространстве, оказывается в пределах его области действия. В пространстве имен можно объявить классы, структуры, делегаты, перечисления, интерфейсы или другие пространства имен.