Я думаю, что вы путаете (неправильное) использование событий в 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
, и все они будут запускаться автоматически, но я никогда не видел, чтобы кто-нибудь делал это. Лично я предпочитаю подход переопределения - я думаю, что он немного понятнее, и у вас никогда не возникнет вопроса «почему я подписан на свои собственные события?».