委托和事件之间的区别是什么?两者不都持有可以执行的函数的引用吗?


当前回答

除了语法和操作属性之外,还有语义上的差异。

从概念上讲,委托是函数模板;也就是说,它们表达了一个函数必须遵守的契约,以便被认为是委托的“类型”。

事件代表……嗯,事件。它们的目的是在发生事情时提醒某人,是的,它们遵循委托定义,但它们不是同一件事。

即使它们是完全相同的东西(在语法上和IL代码中),仍然会存在语义差异。一般来说,我更喜欢对两个不同的概念使用两个不同的名称,即使它们以相同的方式实现(这并不意味着我喜欢使用两次相同的代码)。

其他回答

Event声明在委托实例上添加了一层抽象和保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标。

除了语法和操作属性之外,还有语义上的差异。

从概念上讲,委托是函数模板;也就是说,它们表达了一个函数必须遵守的契约,以便被认为是委托的“类型”。

事件代表……嗯,事件。它们的目的是在发生事情时提醒某人,是的,它们遵循委托定义,但它们不是同一件事。

即使它们是完全相同的东西(在语法上和IL代码中),仍然会存在语义差异。一般来说,我更喜欢对两个不同的概念使用两个不同的名称,即使它们以相同的方式实现(这并不意味着我喜欢使用两次相同的代码)。

对于生活在2020年的人们来说,想要一个干净的答案……

定义:

Delegate:定义一个函数指针。 事件:定义 (1)受保护接口,以及 (2)操作(+=,-=),和 (3)优点:你不再需要使用new关键字。

关于形容词protected:

// eventTest.SomeoneSay = null;              // Compile Error.
// eventTest.SomeoneSay = new Say(SayHello); // Compile Error.

还要注意来自微软的这一部分:https://learn.microsoft.com/en-us/dotnet/standard/events/#raising-multiple-events

代码示例:

委托:

public class DelegateTest
{
    public delegate void Say(); // Define a pointer type "void <- ()" named "Say".
    private Say say;

    public DelegateTest() {
        say  = new Say(SayHello);     // Setup the field, Say say, first.
        say += new Say(SayGoodBye);
        
        say.Invoke();
    }
    
    public void SayHello() { /* display "Hello World!" to your GUI. */ }
    public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}

事件:

public class EventTest
{
    public delegate void Say();
    public event Say SomeoneSay;  // Use the type "Say" to define event, an 
                                  // auto-setup-everything-good field for you.
    public EventTest() {
         SomeoneSay += SayHello;
         SomeoneSay += SayGoodBye;

         SomeoneSay();
    }
    
    public void SayHello() { /* display "Hello World!" to your GUI. */ }
    public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
}

参考:

事件和委托——解释c#中事件和委托模式之间的重要区别,以及它们为什么有用。: https://dzone.com/articles/event-vs-delegate

您还可以在接口声明中使用事件,但委托则不是这样。

An event in .net is a designated combination of an Add method and a Remove method, both of which expect some particular type of delegate. Both C# and vb.net can auto-generate code for the add and remove methods which will define a delegate to hold the event subscriptions, and add/remove the passed in delegagte to/from that subscription delegate. VB.net will also auto-generate code (with the RaiseEvent statement) to invoke the subscription list if and only if it is non-empty; for some reason, C# doesn't generate the latter.

Note that while it is common to manage event subscriptions using a multicast delegate, that is not the only means of doing so. From a public perspective, a would-be event subscriber needs to know how to let an object know it wants to receive events, but it does not need to know what mechanism the publisher will use to raise the events. Note also that while whoever defined the event data structure in .net apparently thought there should be a public means of raising them, neither C# nor vb.net makes use of that feature.