По-прежнему возникают проблемы с пониманием событий ASP.NET. Какой в ​​них смысл? - PullRequest
3 голосов
/ 27 августа 2009

Может быть, я медленный, но я просто не понимаю, почему вы бы использовали событие, которое не является производным от действительного действия (например, нажатия). Зачем проходить через сложную процедуру создания делегатов и событий, когда вы можете просто вызвать метод? Кажется, что когда вы создаете событие, все, что вы делаете, это создаете для вызывающей стороны способ пройти через какой-то сложный процесс, чтобы вызвать простой метод. И звонящий должен сам поднять событие! Я не понимаю.

Или, может быть, я просто не понимаю концепцию. Мне нужны такие события, как OnClick и взаимодействие с элементами управления, но как насчет классов? Я пытался реализовать события для своего класса, скажем, когда источник элемента изменился, но быстро понял, что в этом нет никакого смысла, поскольку я мог просто вызывать метод всякий раз, когда я хочу выполнить определенное действие вместо создания события, поднятие события и написание обработчика события. Кроме того, я могу повторно использовать свой метод, в то время как я не могу обязательно использовать свой обработчик событий.

Кто-то поправил меня, пожалуйста. Я чувствую, что я здесь не прав, и я хочу, чтобы меня поправили. Последний вопрос, который я задал, на самом деле не принес никакого полезного ответа.

Спасибо.

Ответы [ 6 ]

9 голосов
/ 27 августа 2009

Мне всегда нравилась метафора радиостанции.

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

Без этого механизма регистрации (или события). Радиостанция должна будет связаться со всеми радиостанциями по очереди и спросить, хочет ли она трансляции, если ваше радио ответило «да», то отправьте сигнал напрямую.

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

4 голосов
/ 27 августа 2009

События в целом могут быть хорошим способом отделить слушателя / наблюдателя от звонящего / рейзера.

Рассмотрим кнопку. Когда кто-то нажимает на кнопку, происходит событие щелчка. Неужели слушатель нажатия кнопки заботится о том, как выглядит кнопка, или что-то в этом роде? Скорее всего нет. Ему важно только, чтобы действие щелчка имело место, и теперь оно идет и что-то делает.

То же самое можно применить ко всему, что нуждается в такой же изоляции / развязке. Он не обязательно должен управляться пользовательским интерфейсом, это может быть просто логическое разделение, которое должно произойти.

2 голосов
/ 27 августа 2009

Использование событий имеет то преимущество, что отделяет класс (ы), которые обрабатывают события, от классов, которые их вызывают (а-ля Шаблон наблюдателя ). Хотя это полезно для Model View Controller (кнопка, которая вызывает события щелчка, ортогональна классу, который их обрабатывает), она также полезна в любое время, когда вы хотите сделать это легко (во время выполнения или нет). ) сохранить класс, который обрабатывает события, отдельно от класса, который их вызывает (что позволяет вам изменять или заменять их).

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

Edit: Большая часть обработки событий, которую вы будете выполнять в Asp.Net, вероятно, будет обрабатывать события из предоставленных вам классов. Поскольку такие классы используют обработку событий, это упрощает взаимодействие с ними. Часто событие также служит для того, чтобы вы могли взаимодействовать с объектом, вызвавшим событие. Например, элементы управления, связанные с базой данных, обычно инициируют событие непосредственно перед подключением к базе данных, что вы можете обработать, чтобы использовать информацию времени выполнения для изменения аргументов, передаваемых хранимой процедуре при обращении к вашей базе данных, например, если строка запроса содержит параметр номера страницы, а хранимая процедура имеет аргумент номера страницы.

1 голос
/ 27 августа 2009

Я думаю, что вы путаете (неправильное) использование событий в ASP.NET с простой обработкой событий.

Начнем с простой обработки событий. События - это (еще один) способ выполнения принципа «Открыто [для расширения] / Закрыто [для модификации]» . Когда ваш класс представляет событие, он позволяет внешним классам (возможно, классам, о которых даже не думают, а тем более строят), чтобы код выполнялся вашим классом . Это довольно мощный механизм расширения, и он не требует каких-либо изменений вашего класса.

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

class WebServer {
   public event EventHandler<RequestReceivedEventArgs> RequestReceived;

   void ReceiveRequest() {
     // lots of uninteresting network code here
     var e = new RequestReceivedEventArgs();
     e.Request = ReadRequest();
     OnRequestReceived(e);
     WriteResponse(e.Response);
   }

   void OnRequestReceived(RequestReceivedEventArgs e) {
      var h = RequestReceived;
      if (h != null) h(e);
   }
}

Не изменяя исходный код этого класса - возможно, он находится в сторонней библиотеке - я могу добавить класс, который знает, как читать файл с диска:

class FileRequestProcessor {
   void WebServer_RequestReceived(object sender, EventArgs e) {
      e.Response = File.ReadAllText(e.Request);
   }
}

Или, может быть, компилятор ASP.NET:

class AspNetRequestProcessor {
   void WebServer_RequestReceived(object sender, EventArgs e) {
      var p = Compile(e.Request);
      e.Response = p.Render();
   }
}

Или, может быть, мне просто интересно узнать, что событие произошло , не затрагивая его вообще. Скажем, для регистрации:

class LogRequestProcessor {
   void WebServer_RequestReceived(object sender, EventArgs e) {
      File.WriteAllText("log.txt", e.Request);
   }
}

Все эти классы в основном "внедряют" код в середине WebServer.OnRequestReceived.

Теперь, для уродливой части. ASP.NET имеет эту досадную привычку, когда вы пишете обработчики событий для обработки ваших собственных событий . Итак, у класса, который вы наследуете (System.Web.UI.Page), есть событие с именем Load:

 abstract class Page {
    public event EventHandler Load;

    virtual void OnLoad(EventArgs e) {
       var h = this.Load;
       if (h != null) h(e);
    }
 }

и вы хотите запустить код при загрузке страницы. Следуя принципу Open / Closed, мы можем либо наследовать, либо переопределять:

 class MyPage : Page {
    override void OnLoad(EventArgs e) {
       base.OnLoad(e);
       Response.Write("Hello World!");
    }
 }

или использовать события:

 class MyPage : Page {
    MyPage() {
       this.Load += Page_Load;
    }

    void Page_Load(EventArgs e) {
       Response.Write("Hello World!");
    }
 }

По некоторым причинам Visual Studio и ASP.NET предпочитают подход с обработкой событий. Я полагаю, что тогда вы можете иметь несколько обработчиков для события Load, и все они будут запускаться автоматически, но я никогда не видел, чтобы кто-нибудь делал это. Лично я предпочитаю подход переопределения - я думаю, что он немного понятнее, и у вас никогда не возникнет вопроса «почему я подписан на свои собственные события?».

1 голос
/ 27 августа 2009

То, чего вам не хватает, это два:

  • В программном обеспечении есть события, которые могут занять произвольное количество времени не только из-за ожидания ввода данных пользователем (асинхронный ввод-вывод, запросы к базе данных и т. Д.). Если вы запускаете запрос асинхронного ввода-вывода, вы захотите подписаться на событие, уведомляющее вас о завершении чтения, чтобы вы могли что-то сделать с данными. Эта идея обобщена в классе BackgroundWorker .NET, который позволяет выполнять сложные задачи в фоновом режиме (другой поток) и получать уведомления в вызывающем потоке, когда это будет сделано.

  • В программном обеспечении есть случаи, которые используются несколькими клиентами, а не только одним. Например, если у вас есть архитектура плагинов, где ваш основной код предлагает хуки для кода плагинов, вы можете сделать что-то вроде

    foreach (Plugin p in getAvaliablePlugins()) { p.hook1(); } 
    

    в каждом хуке по всему вашему коду, что снижает гибкость (p не может решить, что делать, и должен публично предоставить метод hook1), или вы можете просто

    raiseEvent(hook1,this)
    

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

1 голос
/ 27 августа 2009

События могут использоваться как сообщения для уведомления о том, что что-то произошло, и потребитель может реагировать на них соответствующим образом, поэтому различные компоненты слабо связаны. Есть много вещей, для которых вы можете использовать события, одним примером является аудит событий, происходящих в системе; компонент аудита может потреблять различные события и записывать их в журнал при их запуске.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...