我不明白为什么我们在定义事件时需要event
关键字,而我们可以不使用event
关键字,只使用委托来做同样的事情。
例如:
public delegate void CustomEventHandler(int a, string b);
public event CustomEventHandler customEvent;
customEvent += new CustomEventHandler(customEventHandler);
customEvent(1,"a"); // Raising the event
在这里,如果我从第二行删除event
关键字,那么我还可以通过调用委托来引发事件。
有人能告诉我为什么需要这个event
关键字吗?
7条答案
按热度按时间lskq00tm1#
类似字段的事件和委托类型的公共字段看起来很相似,但实际上有很大的不同。
事件基本上类似于属性-它是一对添加/删除方法(而不是属性的get/set)。当声明类似字段的事件时(即你自己不指定添加/删除位)一个公共事件和一个私有支持字段被创建。这允许你私下引发事件,但允许公共订阅。使用公共委托字段,* 任何人 * 都可以删除其他人的事件处理程序,自己引发事件,等等--这是一场封装灾难。
关于事件(和委托)的更多信息,请阅读我的article on this topic。(在某些时候,我需要为C# 4更新它,它对类似字段的事件做了很小的修改。尽管它的要点仍然是正确的。)
syqv5f0l2#
event关键字有3个不同的作用:
1.可以在接口中定义事件,即使不能在接口中定义常规字段。
1.它将
=
和()
操作符(赋值和调用)的可见性更改为private,以便只有包含类才能调用事件或覆盖其中包含的所有方法。-=
和+=
操作符仍然可以从定义事件的类之外对事件进行调用(它们获得您在事件旁边编写的访问修饰符)。1.您还可以覆盖
-=
和+=
对事件的行为方式。6kkfgxo03#
其他答案都很好;我只是想补充一些其他的思考。
您的问题是“当我们有委托类型的字段时,为什么还需要事件?”我将扩展该问题:如果你有委托类型的字段,为什么你需要方法、属性、事件、示例构造函数或终结器?除了包含值和委托的字段之外,你为什么还需要其他任何东西?为什么不直接说
?
你不需要方法、属性或事件,我们给予你这些东西是因为方法、属性和事件设计模式是重要和有用的,应该有一个标准的、文档化的、清晰的方法来在语言中实现它们。
pgccezyw4#
之所以需要它,部分原因是如果省略了
event
关键字,它会破坏封装。如果它只是一个公共多播委托,任何人都可以调用它,将它设置为null或篡改它。如果一个名为MailNotifier
的类存在,并且它有一个名为MailReceived
的事件,那么其他类型通过调用mailNotifier.MailReceived()
来触发该事件是没有意义的;另一方面,您只能从定义它的类型中干预和调用“类似字段”的事件。
如果你想让你的事件调用保持私有,没有什么可以阻止你做这样的事情:
......但这是一个完整的代码负载,只是(或多或少)做什么场类事件已经给予我们。
u0sqgete5#
与委托字段相比,事件具有明显的优势。事件可以在接口中定义,这与字段相反,增加了代码的抽象性,更重要的是:事件只能从定义类内部调用。在您的情况下,任何人都可以调用事件,可能会破坏您的代码。
有关详细信息,请参见this blog post。
wnavrhmk6#
delegate是一个引用类型,它继承了MulticastDelegate,event是一个修饰符,event是一个委托的特殊修饰符,它修改了一些函数/方法的可访问性,比如Invoke方法,被修饰符事件修改后,一个委托示例变成了一个新的概念“事件”,所以事件只是一个修改过的委托。不能直接更改引用或调用定义Event的类之外的Event,但可以更改引用或调用普通委托示例。Event提供额外的保护,这样事件就有了更多的安全特性.当你在定义事件的类之外时,你可以对事件做两种操作,“+=”和“-=".但是你可以访问所有的公共字段,属性,方法等。下面是一个示例:
lymnna717#
使用网站sharplab.io,您实际上可以反编译“event”关键字的作用。
例如下面的程序:
反编译为以下内容:
所以你可以写和上面一样的代码,只是很罗嗦,容易出错。event关键字会帮你处理这个问题。和其他很多关键字一样,比如async等等。所以它只是语法上的糖衣,仅此而已。
为了好玩,可以尝试使用www.example.com反编译其他关键字sharplab.io。这是一个很好的学习经验。