Самая большая причина, которую я нашел в реальном мире программирования для использования событий и делегатов ослабляя задачу обслуживания кода и поощрения кода повторное использование.
Когда один класс вызывает методы в другом классе, эти классы «тесно связаны». Чем больше классов вы тесно связаны, тем труднее становится превращение в одного из них, не изменяя и другие. В этот момент вы можете написать один большой класс.
Использование событий вместо этого делает вещи более «слабо связанными» и значительно облегчает изменение одного класса, не беспокоя других.
Принимая ваш пример выше, предположим, что у нас был третий класс, Logger
, который должен регистрироваться при отправке электронного письма. Он использует метод, LogEvent(string desc, DateTime time)
, чтобы сделать запись в журнал:
public class Logger
{
...
public void LogEvent(string desc, DateTime time)
{
...//some sort of logging happens here
}
}
Если мы используем методы, нам нужно обновить Email
класс Send
метода для создания экземпляра Logger
и вызвать его LogEvent
метода:
public void Send()
{
//Omitted code that sends.
var logger = new Logger();
logger.LogEvent("Sent message", DateTime.Now);
}
В настоящее время Email
тесно связан с Logger
. Если мы изменим подпись этого метода LogEvent
в Logger
, мы также должны внести изменения в Email
. Вы видите, как это может быстро стать кошмаром, когда вы имеете дело даже с проектом среднего размера? Более того, никто не хочет даже пытаться использовать метод LogEvent
, потому что они знают, что если им нужно что-то изменить, им придется начинать менять другие классы, и то, что должно было быть днем работы, быстро превращается через неделю. Поэтому вместо этого они пишут новый метод или новый класс, который затем становится тесно связанным с тем, что они делают, все становится раздутым, и каждый программист начинает проникать в свое собственное «гетто» своего собственного кода. Это очень, очень плохо, когда вы должны прийти позже и выяснить, что, черт возьми, программа делает или выслеживать ошибку.
Если поставить некоторые события на вашем Email
классе вместо этого, вы можете свободно пара этих классов:
Public Class Email
{
public event EventHandler<EventArgs> Sent;
private void OnSent(EventArgs e)
{
if (Sent!= null)
Sent(this, e);
}
public string To {get;set;}
//Omitted code
public void Send()
{
//Omitted code that sends.
OnSent(new EventArgs());//raise the event
}
}
Теперь вы можете добавить обработчик событий Logger
и subcribe его в Email.Sent
случае от примерно где-нибудь в ваше приложение и это делать то, что нужно сделать:
public class Logger
{
...
public void Email_OnSent(object sender, EventArgs e)
{
LogEvent("Message Sent", DateTime.Now);
}
public void LogEvent(string desc, DateTime time)
{
...//some sort of logging happens here
}
}
и в других местах:
var logger = new Logger();
var email = new Email();
email.Sent += logger.Email_OnSent;//subscribe to the event
Теперь ваши занятия очень слабо связаны и через шесть месяцев после того, как вы решите, что хотите, чтобы ваш Logger
собирал больше или другую информацию или даже делал что-то совершенно другое, когда отправлено электронное письмо, вы можете изменить LogEvent
или обработчиком событий без необходимости касаться класса Email
.Кроме того, другие классы могут также подписаться на событие, не изменяя класс Email
, и вы можете иметь целый ряд вещей, когда отправляется электронное письмо.
Теперь ваш код намного проще, и другие люди гораздо чаще используют ваш код, потому что знают, что им не нужно будет копаться в 20 разных классах, чтобы внести изменения в то, как что-то обрабатывается.
БОЛЬШОЙ РЕДАКТОР: Больше о делегатах. Если вы прочтете здесь: Curiosity is Bliss: C# Events vs Delegates (Я свяжусь с минимумом, я обещаю), вы видите, как автор попадает в то, что события - это в основном специальные типы делегатов. Они ожидают подписи определенного типа (т. Е. (object sender, EventArgs e)
) и могут иметь более одного метода, добавленного к ним (+=
), который должен быть выполнен, когда метод поднят. Существуют и другие различия, но это основные из них, которые вы заметите. Итак, что хорошего - делегат?
Представьте, что вы хотели дать клиенту своего Email
класс некоторые варианты отправки почты. Можно определить ряд методов для этого:
Public Class Email
{
public string To {get;set;}
//Omitted code
public void Send(MailMethod method)
{
switch(method)
{
case MailMethod.Imap:
ViaImap();
break;
case MailMethod.Pop:
ViaPop();
break;
}
}
private void ViaImap() {...}
private void ViaPop() {...}
}
Это хорошо работает, но если вы хотите добавить больше вариантов позже, вы должны изменить свой класс (а также MailMethod
перечисление, которое предполагается здесь). Если объявить делегат вместо этого, вы можете отложить этот вид решения для клиента и сделать ваш класс гораздо более гибким:
Public Class Email
{
public Email()
{
Method = ViaPop;//declare the default method on instantiation
}
//define the delegate
public delegate void SendMailMethod(string title, string message);
//declare a variable of type SendMailMethod
public SendMailMethod Method;
public string To {get;set;}
//Omitted code
public void Send()
{
//assume title and message strings have been determined already
Method(title, message);
}
public void SetToPop()
{
this.Method = ViaPop;
}
public void SetToImap()
{
this.Method = ViaImap;
}
//You can write some default methods that you forsee being needed
private void ViaImap(string title, string message) {...}
private void ViaPop(string title, string message) {...}
}
Теперь клиент может использовать свой класс со своими собственными методами или предоставить свой собственный метод для отправки почте примерно однако они выбирают:
var regularEmail = new Email();
regularEmail.SetToImap();
regularEmail.Send();
var reallySlowEmail = new Email();
reallySlowEmail.Method = ViaSnailMail;
public void ViaSnailMail(string title, string message) {...}
Теперь ваши классы несколько менее тесно связаны и гораздо легче поддерживать (и писать тесты для!). Есть, конечно, и другие способы использования делегатов, и лямбды вроде бы занимают определенные места, но этого должно хватить для введения в голые кости.
Возможный дубликат [Делегаты, почему?] (Http://stackoverflow.com/questions/3567478/delegates-why) –
Спасибо, но в идеале, чтобы по-настоящему оценить это, я надеялся, что я получу ответ на код, который я написал или даже это возможно. –