Категории
Самые читаемые
onlinekniga.com » Компьютеры и Интернет » Программирование » ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен

ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен

Читать онлайн ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 74 75 76 77 78 79 80 81 82 ... 259
Перейти на страницу:

public class CarEventArgs: EventArgs {

 public readonly string msg;

 public CarEventArgs(string message) {

  msg = message;

 }

}

Теперь мы должны обновить делегат CarEventHandler так, как показано ниже (события должны остаться без изменений).

public class Car {

 public delegate void CarEventHandler(object sender, CarEventArgs e);

 …

}

При генерировании событий из метода Accelerate() мы теперь должны предоставить ссылку на текущий объект Car (с помощью ключевого слова Car) и экземпляр нашего типа CarEventArgs.

public void Accelerate(int delta) {

 // Если машина сломалась, генерируется событие Exploded.

 if (carIsDead) {

  if (Exploded != null) Exploded(this, new CarEventArgs("Извините, машина сломалась…"));

  else {

   …

   AboutToBlow(this, new CarEventArgs("Осторожно! Могу сломаться!"));

  }

  …

 }

}

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

public static void CarAboutToBlow(object sender, CarEventArgs e) { Console.WriteLine ("{0} сообщает: {1}", sender, e.msg); }

Если получатель желает взаимодействовать с объектом, отправившим событие, следует выполнить явное преобразование System.Object. Так, если нужно выключить радио, когда объект Car уже на полпути к своему создателю, можно предложить обработчик событий, который будет выглядеть примерно так.

public static void CarIsAlmostDoomed(object sender, CarEventArgs e) {

 // Просто для гарантии здесь перед вызовом предлагается

 // проверка среды выполнения.

 if (sender is Car) {

  Car с = (Car)sender;

  c.CrankTunes(false);

 }

 Console.WriteLine("Важное сообщение от {0}: {1}", sender, e.msg);

}

Исходный код. Проект PrimAndProperCarEvenfs размещен в подкаталоге, соответствующем главе 8.

Анонимные методы в C#

В завершение этой главы мы рассмотрим некоторые связанные с делегатами и событиями возможности .NET 2.0 через призму возможностей C#. Для начала обратим внимание на то, что в случае, когда вызывающей стороне требуется осуществлять прием поступающих событий, необходимо определить уникальный метод, отвечающий виду соответствующего делегата.

class SomeCaller {

 static void Main(string[] args) {

  SomeType t = new SomeType();

  t.SomeEvent += new SomeDelegate(MyEventHandler);

 }

 // Как правило, вызывается только объектом SomeDelegate.

 public static void MyEventHandler() {…}

}

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

Чтобы разрешить эту проблему, теперь позволяется ассоциировать делегат непосредственно с блоком операторов программного кода при регистрации события. Формально такой программный код называется анонимным методом. В качестве иллюстрации базового синтаксиса рассмотрите следующий метод Main(), в кото-рам посылаемые типом Car события обрабатываются о помощью анонимных методов, а не специальных именованных программ обработки событий.

class Program {

 static void Main(string[] args) {

  Console.WriteLine("***** Анонимные методы *****n");

  Car c1 = new Car("SlugBug", 100, 10);

  // Регистрация обработчиков событий с помощью

  // анонимных методов.

  c1.AboutToBlow += delegate {

   Console.WriteLine("Оx! Едем слишком быстро!");

  };

  c1.AboutToBlow += delegate(object sender, CarEventArgs e) {

   Console.WriteLine("Сообщение от Car: {0}", e.msg);

  };

  c1.Exploded += delegate(object sender, CarEventArgs e) {

   Console.WriteLine("Фатальное сообщение от Car: {0}", e.msg);

  };

  …

 }

}

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

Обратите вниманий на то, что тип Program уже не определяет конкретные статические программы обработки событий, такие как, например, CarAboutToBlow() и CarExploded(). Вместо этого здесь указаны безымянные (т.е. анонимные) методы, определяемые "внутристрочно" в тот момент, когда вызывающая сторона обрабатывает событие, используя синтаксис +=.

Базовый синтаксис анонимного метода соответствует следующему представлению в псевдокоде.

class SomeCaller {

 static void Main(string[] args) {

  SomeType t = new SomeType();

  t.SomeEvent += delegate(необязательныеАргументыДелегата) { /* операторы */};

 }

}

В предыдущем варианте метода Main() следует обратить внимание на то, что при обработке первого события AboutToBlow мы не определяем аргументы, передаваемые делегатом.

c1.AboutToBlow += delegate {

 Console.WriteLine("Ox! Едем слишком быстро!");

};

Строго говоря, получать входные аргументы, посылаемые конкретным событием, не обязательно. Но если вы хотите использовать поступающие аргументы, вы должны указать параметры, прототипы которых заданы типом делегата (как это сделано во втором случае обработки событий AboutToBlow и Exploded). Например:

c1.AboutToBlow += delegate(object sender, CarEventArgs e) {

 Console.WriteLine("Важное сообщение от Car: {0}", e.msg);

};

Доступ к "внешним" переменным

Анонимные методы интересны в том отношении, что они позволяют доступ к локальным переменным определяющего их метода. Формально говоря, такие переменные являются "внешними переменными" анонимного метода. Для примера предположим, что наш метод Main() определяет локальную целую переменную-счетчик с именем aboutToBlowCounter. В рамках анонимных методов, обрабатывающих событие AboutToBlow, мы будем увеличивать этот счетчик на 1 и печатать его значение в конце Main().

static void Main(string[] args) {

 …

 int aboutToBlowCounter = 0;

 // Создание машины.

 Car c1 = new Car("SlugBug", 100, 10);

 // Регистрация обработчиков событий в виде анонимных методов.

 c1.AboutToBlow += delegate {

  aboutToBlowCounter++;

  Console.WriteLine("Ox! Едем слишком быстро!");

 };

 c1.AboutToBlow += delegate(string msg) {

  aboutToBlowCounter++;

  Console.WriteLine("Важное сообщение от Car: {0}", msg);

 };

 …

 Console.WriteLine("Событие AboutToBlow вызывалось {0} раз(а).", aboutToBlowCounter);

 Console.ReadLine();

}

В результате выполнения этого обновленного метода Main() завершающий оператор Console.WriteLine() сообщит вам о том, что событие AboutToBlow генерировалось дважды.

Замечание. Анонимный метод не имеет возможности получить доступ к параметрам ref и out определяющего метода.

Групповое преобразование методов в C#

Еще одной связанной с делегатами и событиями возможностью в C# является так называемое групповое преобразование методов. Эта возможность позволяет регистрировать "просто" имя обработчика событий. Чтобы пояснить это на примере, мы снова рассмотрим тип SimpleMath, уже рассматривавшийся в этой главе выше, но добавим в него новое событие, которому будет назначено имя ComputationFinished.

public class SimpleMath {

 // Здесь мы не утруждаем себя созданием

 // производного типа System.EventArgs.

 public delegate void MathMessage(string msg);

 public event MathMessage ComputationFinished;

 public int Add(int x, int y) {

  ComputationFinished("Сложение выполнено.");

  return х + y;

 }

 public int Subtract(int x, int y) {

  ComputationFinished("Вычитание выполнено.");

  return x – у;

 }

}

Если не использовать синтаксис анонимных методов, то мы должны обработать событие ComputationComplete так, как показано ниже.

class Program {

 static void Main(string[] args) {

  SimpleMath m = new SimpleMath();

  m.ComputationFinished += new SimpleMath.MathMessage(ComputationFinishedHandler);

  Console.WriteLine("10 + 10 равно {0}", m.Add(10, 10));

  Console.ReadLine();

 }

 static void ComputationFinishedHandler(string msg) { Console.WriteLine(msg); }

}

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

1 ... 74 75 76 77 78 79 80 81 82 ... 259
Перейти на страницу:
На этой странице вы можете бесплатно читать книгу ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - Эндрю Троелсен.
Комментарии