2010-06-12 51 views
76

我不明白为什么我们在定义事件时需要“event”关键字,而我们只需使用委托就可以在不使用“event”关键字的情况下做同样的事情。为什么我们在定义事件时需要“事件”关键字?

例如

public delegate void CustomEventHandler(int a, string b); 
public event CustomEventHandler customEvent; 
customEvent += new CustomEventHandler(customEventHandler); 
customEvent(1,"a"); // Raising the event 

在这里,如果我从第二行删除“事件”的关键字,那么我也可以通过调用委托引发事件。任何人都可以告诉我为什么这个事件关键字需要?

+0

确定如果您没有使用event关键字任何可以使用类对象访问该事件的人将其设置为NULL,如objClass.SelectedIndexChanged = null。这会使您的底层代码崩溃。事件关键字强制用户使用+ =分配与委托类似的内容。 – 2013-07-05 07:57:24

回答

92

田野般的活动和代表类型的公共领域看起来类似,但实际上是非常不同的。

事件基本上就像一个属性 - 它是一对添加/删除方法(而不是一个属性的get/set)。当你声明一个类似字段的事件(即你没有自己指定添加/删除位的事件)时,将创建一个公共事件和一个专用的后台字段。这可以让你私下提出事件,但允许公开订阅。使用公共代理字段,任何人都可以删除其他人的事件处理程序,自己提出事件等 - 这是封装灾难。

有关活动(和代表)的更多信息,请阅读我的article on this topic。 (在某些时候,我需要为C#4进行更新,这会稍微改变类似于场景的事件,但它的要点仍然是正确的。)

+4

这比MSDN的官方单行解释要好上千倍:'event关键字用于在发布者类中声明一个事件。' – cowlinator 2016-04-13 18:17:38

5

部分需要它,因为如果您省略event关键字,它会中断封装。如果它只是一个公共多播委托,任何人都可以调用它,将其设置为null或篡改它。如果存在名为MailNotifier的类并存在名为MailReceived的事件,则其他类型通过调用mailNotifier.MailReceived()来触发该事件是没有意义的;

另一方面,您只能插入并调用定义它的类型的“字段”事件。

如果你想保持你的事件调用私有的,没有什么可以阻止你做这样的事情:

public class MyClassWithNonFieldLikeEvent 
{ 
    private CustomEventHandler m_delegate; 

    public void Subscribe(CustomEventHandler handler) 
    { 
     m_delegate += handler;   
    } 

    public void Unsubscribe(CustomEventHandler handler) 
    {   
     m_delegate -= handler; 
    } 

    private void DoSomethingThatRaisesEvent() 
    { 
     m_delegate.Invoke(...); 
    }  
} 

......但这是一个代码整个负载刚(或多或少)做什么田野般的事件已经给我们。

+0

设计师使用这些东西也会比较困难......你基本上会依赖方法的命名约定,而不是公开的元数据说“这是一个事件”。 – 2010-06-12 13:07:42

3

与委托字段相比,事件具有明显的优势。可以在接口中定义事件,而不是字段,为代码添加抽象,更重要的是:事件只能从定义类中调用。在你的情况下,任何人都可以调用该事件,可能会破坏你的代码。

有关更多信息,请参阅this blog post

+2

你不应该真的在比较事件和*委托* - 比较事件和*公共字段与委托类型*。不,框架*不需要事件签名。您可以创建您喜欢的任何代理类型的事件。 – 2010-06-12 13:12:38

+0

非常感谢。从书中不清楚。 – teenup 2010-06-12 13:14:29

+0

谢谢乔恩,固定。 – Femaref 2010-06-12 13:17:29

16

事件关键字做3件不同的事情:

  1. 您可以在接口定义事件,即使你不能在接口定义常规领域。
  2. 它将=()运算符(赋值和调用)的可见性更改为private,以便只有包含的类才能调用该事件或覆盖其中包含的所有方法。 -=+=运算符仍然可以在定义类的外部事件上调用(它们获得您在事件旁边编写的访问修饰符)。
  3. 您也可以覆盖-=+=的行为方式。
+0

检查http://pastebin.com/TMpib9ux我提供了一些例子。 :) – 2016-03-23 18:54:54

+0

非常明确的解释 – lucasasecas 2017-05-08 19:00:26

16

其他答案很好;我只想添加其他内容来思考。

你的问题是“当我们有委托类型的字段时,为什么我们需要事件?”我会扩展这个问题:如果你有委托类型的字段,为什么你需要方法,属性,事件,实例构造函数或终结器?为什么你需要什么以外的字段包含值和委托类型?为什么不只是说

class C 
{ 
    private int z; 
    public readonly Func<int, int> M = (int x)=>{ return x+z; } 
    // ... and so on 
} 

您不需要需要方法,属性或事件。我们给你这些东西,因为方法,属性和事件设计模式是重要和有用的,并且应该有一个标准的,有记录的,清晰的方式来用语言来实现它们。

+1

哇!它提醒我为什么爱c#!在我所使用的所有语言中,它具有紧凑性,灵活性和可读语义的恰当平衡。唯一可比较的语言是Object Pascal。 – 2013-02-21 20:51:51

+0

这不是他所要求的。他问了一个合理的问题,为什么我们需要事件关键字,即它什么都不做。它有什么区别,它什么时候有用。你的问题等同于为什么我们需要方法和属性,为什么我们需要对象,为什么要OOP,为什么要使用方法,为什么要使用程序,为什么不是命令式编程。而且你说“因为它很有用”。很明显。他特别要问,不是为什么方法是有用的,不是为什么OOP有用。只是说事件关键字是有用的,不会说明为什么。 – barlop 2017-02-03 16:41:34

+0

@barlop:好吧,如果你不喜欢这个问题,随时写一个你更喜欢这个七岁的问题的答案。这样整个网站变得更好。 – 2017-02-03 17:20:44

相关问题