gpt4 book ai didi

c# - 事件和委托(delegate)与调用方法

转载 作者:太空狗 更新时间:2023-10-30 00:24:09 25 4
gpt4 key购买 nike

我希望这个问题不是与其他人密切相关,但其他人似乎并没有填补知识空白。

这似乎是尝试理解事件和委托(delegate)的热门话题,在阅读了许多 SO 问题和 MSDN 文章后,我恐怕还是不明白。在创建出色的 Web 应用程序几年后,我发现自己对不理解它们感到非常沮丧。请任何人都可以在通用代码中澄清这一点。所以问题是,为什么要使用事件和委托(delegate)来调用方法?

下面是我在工作中编写的一些基本代码。我能否利用事件和委托(delegate)?

Public Class Email
{
public string To {get;set;}
//Omitted code

public void Send()
{
//Omitted code that sends.
}
}

Public Class SomeClass
{
//Some props

Public void DoWork()
{
//Code that does some magic

//Now Send Email
Email newEmail = new Email();
newEmail.To = "me@me.com";
newEmail.Send();
}
}

这可能不是最好的例子,但无论如何 DoWork() 方法可以订阅电子邮件?这行得通吗?对我真正了解事件和代表的任何帮助将不胜感激。

问候,

最佳答案

我在实际编程中发现使用事件和委托(delegate)的最大原因是减轻了 的任务。代码维护鼓励代码重用 .

当一个类调用另一个类中的方法时,这些类是“紧密耦合的”。紧密耦合的类越多,对其中一个进行更改而不必同时更改其他几个的难度就越大。那时您可能已经编写了一个大类。

相反,使用事件会使事情变得更加“松散耦合”,并且可以更轻松地更改一个类而不必打扰其他类。

以上面的例子为例,假设我们有第三个类,Logger ,应该在发送电子邮件时记录。它使用一种方法,LogEvent(string desc, DateTime time) , 将条目写入日志:

public class Logger 
{
...
public void LogEvent(string desc, DateTime time)
{
...//some sort of logging happens here
}
}

如果我们使用方法,我们需要更新您的 Email类(class)' 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方法,因为他们知道如果他们需要对其进行任何形式的更改,他们将不得不开始更改其他类(class),而本应一个下午的工作很快就会变成一周。因此,相反,他们编写了一个新方法或一个新类,然后与他们正在做的任何其他事情紧密耦合,事情变得臃肿,每个程序员开始进入他们自己的代码的小“贫民窟”。当您必须稍后进入并弄清楚程序在做什么或寻找错误时,这非常非常糟糕。

如果你把一些事件放在你的 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 添加事件处理程序并将其订阅到 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

现在您的类(class)非常松散耦合,六个月后,当您决定想要您的 Logger 时。要捕获更多或不同的信息,甚至在发送电子邮件时执行完全不同的操作,您可以更改 LogEvent方法或事件处理程序,而无需触摸 Email类(class)。此外,其他类也可以订阅该事件而无需更改 Email类,并且您可以在发送电子邮件时发生很多事情。

现在维护您的代码要容易得多,其他人更有可能重用您的代码,因为他们知道他们不必为了改变某些事情的处理方式而深入挖掘 20 个不同类的内容。

大编辑:更多关于代表。如果您阅读这里: Curiosity is Bliss: C# Events vs Delegates (我保证将链接保持在最低限度),您会看到作者如何理解事件基本上是特殊类型的委托(delegate)这一事实。他们期望某个方法签名(即 (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 枚举)。如果您改为声明委托(delegate),则可以将此类决定推迟到客户端,并使您的类更加灵活:
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) {...}

现在,您的类的耦合度有所降低,并且更易于维护(并为其编写测试!)。当然还有其他使用委托(delegate)的方法,而 lambda 则使事情更上一层楼,但这对于简单介绍就足够了。

关于c# - 事件和委托(delegate)与调用方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28914506/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com