使用特定示例了解 C# 中的委托和事件
本文关键字:事件 了解 | 更新日期: 2023-09-27 17:50:23
所以我已经到了理解事件和代表的地步。
我过度理解代表的用法。关于委托,我唯一关心的是是否可以将委托配置为使用与事件无关的函数......如果是,如何为委托定义的函数编写逻辑?(我想这样的功能并没有多大意义,但很高兴知道。
至于事件...我很难理解它。我明白事件是一个函数,当代码中发生某些事情时执行。但是,我没有得到创建事件的过程。部分地。
对于这个问题,我将使用加里·威洛比(Gary Willoughby(的回答:https://stackoverflow.com/a/803528/1104766它发布在一个我试图理解整个主题的问题上。
我在上面的例子中没有得到什么:MyObject.OnMaximum += new MyEventHandler(MaximumReached);
首先,如何创建一个委托的实例,并在需要 2 个变量时只传递 1 个变量?一定是我错过了什么...
关于这一行的第二件事是,new ...()
实例被添加到驻留在MyObject
中的OnMaximum
函数中,该函数是MyClass
的实例 - 如果可以做这样的事情,究竟是什么OnMaximum
?它也从未真正定义过!
if(OnMaximum != null) {
OnMaximum(this, new MyEventArgs("You've entered " +
value.ToString() +
", but the maximum is " +
Maximum.ToString()));
}
至于这部分,OnMaximum
被称为,但它的逻辑从未在代码的任何地方真正定义过,那么结果会是什么?显然,我猜应该是文字"你已经输入了......"。但我的问题是更具体地说,函数/事件收到的值到底发生了什么?
为了清楚起见,我用粗体标记了所有问题。
附言,我知道这个问题通常已经发布了几次。
请注意,此特定问题是指其他成员撰写的答案,此处提出的问题特定于此示例。这就是为什么在谷歌中找不到这样的答案。
不过,为了记录,我在发布之前确实进行了搜索,并且我确实尝试了理解,但我想示例是我理解某些东西的最佳方式,尤其是当我缺乏英语CS词汇知识时。
我想你可能患有过量的句法糖!
你看,所有事件都是一个委托。 实际上,老实说,这是一个可能被null
的代表集合。
让我们举个例子:
public class Alarm
{
public delegate void AlarmEvent();
// my secret stuff
// raise it!
public void Ring()
{
if(OnAlert != null)
OnAlert();
}
public event AlarmEvent OnAlert;
}
所有的事件关键字在这里为我们提供的,是添加和删除该事件的侦听器的能力......
Alarm a = new Alarm();
a.OnAlert += myevent;
a.OnAlert += myotherevent;
另一方面,委托的工作方式与我们刚才描述的完全一样,但更类似于函数指针。 想象一个抽象渲染器,我可以这样制作类:
public abstract class Renderer
{
protected abstract void RenderImpl();
}
这意味着,我必须从该渲染中得出。 但是,如果该渲染器接受委托呢?
public abstract class Renderer
{
public delegate void RenderDelegate();
public Renderer(RenderDelegate) { /* ... */ }
}
我们现在正在分离构图。
我得到了什么? 好不好? 就事件而言,我允许公众成为我班级的观察者。 他们可以做出反应。 在第二种情况下,我定义一个用户提供的委托来执行利基功能,同时我保留大部分控制权。
委托和事件大多是一回事 - 但我们所做的设计选择决定了哪一个是合适的。
为了解决您的其他问题,您提出了一个事件与委托的很好的例子。 如果我们要更改上面的警报类,以允许委托返回true
或false
,那么会发生什么?
我们会得到几个观察者返回 true,但谁是对的,我们如何检查它们?
然而,沿着单一代表路线... "渲染成功"或"渲染失败"。 更改此单个委托并不是什么大问题。 我们可以预测地测试我们的渲染器是否完成了这项工作:
if(!delegate_->Invoke())
fallBackCode();
我们不能在事件中做到这一点。 好吧,不可预测。
更简单地说,当您想广播某些内容并让其他人在收到该事件后执行某些操作时,事件就存在。 炸弹爆炸了... 奔跑,躲藏,打电话给国民警卫队,关掉烤箱,或者躲避和掩护。
委托允许您在不更改模型的情况下更改功能(委托遵循签名! 代表的一个很好的例子是当你打电话给List<T>.Sort
时。 那是代表。 它有一个签名。
但是您也可以将它们用于更高级的事情,例如在不诉诸接口的情况下更改Renderer
类,以及能够提供用户定义的"代码片段"。 我想这里最简单的类比是 Win32 中的所有者绘制的控件。 无需覆盖整个类,无需提供接口并编写大量代码。 只需更改在组合框中呈现项目的位即可。 代表们是你如何实现这一目标的很好的例子。
MSDN 的教程将回答您的所有问题:
代表: http://msdn.microsoft.com/en-us/library/aa288459(v=vs.71(.aspx
事件:http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71(.aspx
class Program
{
static void Main(string[] args)
{
Parent p = new Parent();
}
}
////////////////////////////////////////////
public delegate void DelegateName(string data);
class Child
{
public event DelegateName delegateName;
public void call()
{
delegateName("Narottam");
}
}
///////////////////////////////////////////
class Parent
{
public Parent()
{
Child c = new Child();
c.delegateName += new DelegateName(print);
//or like this
//c.delegateName += print;
c.call();
}
public void print(string name)
{
Console.WriteLine("yes we got the name : " + name);
}
}
加油伙计们!你们所有人都成功地使代表们:)复杂化!
我将尝试在这里留下一个提示:一旦我在 Javascript 中意识到 jquery ajax 调用,我就理解了代表。 例如:ajax.send(url, data, successcallback, failcallback( 是函数的签名。 如您所知,它将数据发送到服务器 URL,作为响应,它可能是 200OK 或其他错误。如果发生任何此类事件(成功/失败(,您需要执行一个函数。因此,这就像一个函数的占位符,能够提及成功或失败。该占位符可能不是很通用 - 它可能接受一组参数,并且可能/可能不会返回值。这种占位符的声明,如果在 C# 中完成,则称为委托!由于 javascript 函数对参数数量不严格,您只会将它们视为通用占位符......但是 C# 有一些严格的声明...这归结为代表声明!!
希望对您有所帮助!