C#中的委托和事件有什么区别?

Stu*_*ens 41 c#

可能重复:
委托和事件之间有什么区别?

我在面试时得到的这个问题,我仍然不知道答案应该是什么.
我很感激任何想法!

Jon*_*eet 64

我有一篇非常准确的文章

简而言之,您可以将事件视为有点像属性 - 但它没有获取/设置操作,而是添加/删除.添加/删除的值始终是委托引用.

代表们自己支持以下行动:

  • 合并(将多个委托实例链接在一起)
  • 删除(再次拆分)
  • 调用(同步或异步)
  • 找出目标,调用列表等各种事情

请注意,委托本身是不可变的,因此合并/删除操作会返回新的委托实例,而不是修改现有的委托实例.

  • @AshishJain:是的,确切地说.请参阅链接文章中的"重点". (2认同)

Eri*_*ert 50

到目前为止,其他答案都非常好.这是考虑它的另一种方式.

属性字段之间的语义差异是什么?我不是说什么是技术差异,就像一个属性实际上是一对方法,等等等等等等.我的意思是,就理解程序的含义而言,有什么区别?

属性通常是类的公共成员,它表示正在建模的事物的属性.也就是说,你想制作一份报纸模型,这样你就可以制作一份报纸,然后给它一个属性发布者.出版商是报纸的财产,因此出版商是报纸类的财产.

字段通常是类的实现细节.也许Publisher属性实际上是作为字段实现的.但报纸上没有"字段",因此您不要将发布商字段作为报纸类的公共成员公开; 您将它用作Publisher属性的私有实现细节.

事件和代表有点类似.事件是模型中的事物.按钮是一个可以在单击时通知您的按钮,因此Button类具有"Click"事件.实际执行通知的委托是事件的实现细节.


Kon*_*lph 18

基本上,委托只是C(或函数指针列表)中的函数指针的包装器.

一个事件是一个更高级别的抽象,它包装一个委托的概念与方法订阅和取消订阅的方法,以这样的代表在一起.

事件是一个"属性",它公开一个addremove方法(通过代码调用+=-=在代码中调用)以向代理列表添加/删除订阅者.


Tho*_*que 8

代表类似于在C/C的函数指针++.它包含对方法和对象实例的引用(如果该方法是非静态的).代表通常是多播的,即它们包含对几个对象/方法对的引用.

一个事件是一个通知机制的基础上,与会代表.它公开披露的唯一内容是一对方法(添加/删除)来订阅或取消订阅通知.委托类型用于定义处理程序方法的签名,订阅者列表(通常)在内部存储为委托.


Jed*_*Jed 8

我很乐意承认这个答复没有比较代表和事件之间的区别.但是,我认为其他人为活动提供的回复以及对代表的更详细解释,您会看到两者之间的差异.更具体地说,一旦你对代表有了更清楚的了解,我认为你将在代表和事件之间获得概念上的区别.

什么帮助我理解代表是什么,将它们视为仅仅是单个方法的容器.

为了概念化委托如何是方法的"容器",请查看此示例,该示例使用委托来调用三种不同的方法 - 请注意,尽管使用相同的委托实例来调用三种不同的方法,但委托实例仅包含(或目标)在任何给定时间的一种方法.

class Program
{
    delegate void MyDelegate();

    static void Main()
    {            
        //Notice how we use the same delegate instance
        //to target different methods of the same signature

        MyDelegate myDelegate = new MyDelegate(MethodA);
        myDelegate(); //Invoke the method
        myDelegate = MethodB;
        myDelegate();
        myDelegate = MyClass.MethodZ;
        myDelegate();

        Console.ReadLine();
    }

    static void MethodA()
    {
        Console.WriteLine("Method 'A' is doing work.");
    }

    static void MethodB()
    {
        Console.WriteLine("Method 'B' is doing work.");
    }

    class MyClass
    {
        public static void MethodZ()
        {
            Console.WriteLine("Method 'Z' of MyClass is doing work");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您会注意到示例中的委托可以包含/ target任何与委托具有相同签名的方法(在我们的示例中返回void并接受零参数).如果你在这里暂停并消化这个原则,你就可以开始理解代表了.

有了这样说,让我对代表感到困惑的是,当我在代码中明确地实现委托时.上面的示例程序明确地使用了委托,但没有实际的理由这样做,因为Main()方法也可以直接调用目标方法 - 即我们刚刚完成...

static void Main()
{
    MethodA();
    MethodB();
    MyClass.MethodZ();

    Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)

那么什么时候我们明确地实现委托呢?他说,Jon Skeet帮我回答了这个问题

...您可以将委托类型视为有点像单个方法的接口.

知道委托是方法的容器,现在,考虑到委托就像具有单个方法的接口,请考虑以下事项:

假设我们有一个程序可以启动不同类型车辆的引擎 - 汽车,摩托车和飞机.

我们的计划将包括车辆类 - 每种车型一类.每个车辆类别负责启动自己的发动机.此外,类似于实现接口,每个类将确保其启动其自己的引擎的方法将具有所有其他类(和Main)同意的指定签名.

所以我们有这样的事情:

class VehicleProgram
{
    //All vehicle classes implement their own engine starter method that has this signature
    delegate void StartEngine();
    static void Main()
    {
        //The Main doesn't know the details of starting an engine.
        //It delegates the responsibility to the concrete vehicle class
        foreach (StartEngine starter in GetVehicleStarters())
        {
            starter(); //Invoke the method
        }

        Console.ReadLine();
    }

    static List<StartEngine> GetVehicleStarters()
    {
        //Create a list of delegates that target the engine starter methods
        List<StartEngine> starters = new List<StartEngine>();

        starters.Add(Car.StartCar);
        starters.Add(Motorcycle.StartMotorcycle);
        starters.Add(Airplane.StartAirplane);

        return (starters);
    }

    class Car
    {
        public static void StartCar()
        {
            Console.WriteLine("The car is starting.");
        }
    }

    class Motorcycle
    {
        public static void StartMotorcycle()
        {
            Console.WriteLine("The motorcycle is starting.");
        }
    }

    class Airplane
    {
        public static void StartAirplane()
        {
            Console.WriteLine("The airplane is starting.");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

由于委托持有方法,我们能够实现一个设计,其中Main()只获取委托列表然后调用该方法.这种设计与我们实现接口的方式非常相似.

阅读更多关于何时使用代理而不是接口的信息