Книга: C# для профессионалов. Том II

События

События

События C# предоставляют значительно более надежный и гибкий паттерн наблюдателя, чем в Java. Более того, они могут быть объявлены либо как поля, либо как свойства. Создание события является процессом из трех частей. Сначала мы получаем делегата, а затем событие, связанное с этим делегатом, и наконец, когда происходит некоторое действие, вызывается событие.

Проиллюстрируем это, удаляя исключения из класса Properties и используя вместо этого события. Наиболее привлекательным свойством событий является гибкость, которая наблюдается при использовании модели делегата. По сути можно использовать любую специальную сигнатуру, которую желательно связать с событием, а затем подписчик на событие должен предоставить целевой метод, который соответствует требуемому списку параметров. Создание этой специальной сигнатуры начинается с определения делегата в коде пространства имен. Для класса Properties необходимо, чтобы он инициировал строковые события, аналогичные исключениям, которые необходимо порождать:

public delegate void ObservableDelegate(string message);

Затем объявляется delegate как поле event в классе:

public event ObservableDelegate ExceptionEventListener;

Наконец, переписывается реализация индексатора для активизации приемника события всякий раз, когда возникает условие исключения:

public string this[string а] {
 get {
  if (a.Equals("Age")) {
   return int.ToString(age);
  } else if (a.Equals("Name")) {
   return name;
  } else {
ExceptionEventListener(can only accept 'name' or 'age' key");
   return null; // поток программы продолжается после того, как
                // событие было инициировано, поэтому необходимо
                // вернуть значение. В этом случае, так как ключ
                // является недействительным (не 'name' или 'age'),
                // возвращается null, указывая отсутствие значения
  }
 }
 set {
  if (a.Equals("Age") {
   age = int.Parse(value);
  }
  else {
   listener(a+ " is read only or does not exist");
  }
 }
}

Экземпляр делегата, связанный с приемником событий, никогда не создается. Это объясняется тем, что создание экземпляра реально происходит на клиенте, который потребляет это событие. Для клиента событие представляется как открытое поле, но не надо думать, что оно не имеет ограничений. Единственными возможными действиями по отношению к полю события являются:

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

? Удаление экземпляров делегатов из события

C# использует операторы += и -= соответственно для добавления и удаления экземпляров делегатов из событий. Оба оператора одинаковы в C# и Java. Недопустимо задавать событие, равным одному любому экземпляру делегата. Вместо этого можно добавить в событие столько делегатов, сколько понадобится. Это свободно транслируется в требуемое количество приемников событий для одного события. Пример ниже показывает, как это можно сделать:

public delegate void TestEvent();
public class Tester {
 public event TestEvent testEvent;
 Tester() { }
 public void Perform() {
  testEvent();
 }
 public class Client {
  Client() {
   Tester tester = new Tester();
   TestEvent a = new TestEvent(Callback1); // сначала создать делегата
   tester.testEvent += a; // затем добавить его
   tester.testEvent += new Test(CallBack2); // или можно сделать это
                                            // за один проход
   tester.testEvent += new Test(Callback3);
   tester.testEvent += new Test(Callback4);
   tester.Perform();
  }
  public void CallBack1() {
   // уведомить через e-mail)
  }
  public void CallBack2() {
   // послать факсы
  }
  public void CallBack3() {
   // послать беспроводное сообщение
  }
  public void CallBack4() {
   // сохранить в журнале
  }
 }
}

Как можно понять из приведенного примера, чтобы использовать события класса, необходимо сначала получить метод в классе подписчиков для обработки события (очень похоже на то, как действуют делегаты), затем добавить методы обработки события в событие. Давайте создадим статический метод Notify():

public static void Notify(string i) {
 Console.WriteLine(i);
}

Этот метод использует такую же сигнатуру, что и приемник событий класса Properties. В методе Main можно зарегистрировать метод Notify() и задать условно ошибку, чтобы протестировать событие:

Properties props = new Properties("hello"); // зарегистрировать обработчик событий
props.ExceptionEventListener += new ExceptionEventListener(test);
p["Aged"] = "35"; // неправильный ключ используется
                  // для моделирования ошибки

Оглавление книги


Генерация: 0.230. Запросов К БД/Cache: 0 / 0
поделиться
Вверх Вниз