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

时间:2011-03-22 15:24:01

标签: c#

  

可能重复:
  What is the difference between a delegate and events?

我在接受采访时遇到的这个问题,我仍然不知道答案应该是什么 我很感激任何想法!

7 个答案:

答案 0 :(得分:62)

我的article非常完全

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

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

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

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

答案 1 :(得分:49)

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

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

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

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

事件和代表有点类似。事件是模型中的 。按钮是一个可以在单击时通知您的按钮,因此Button类具有“Click”事件。实际进行通知的代表是事件的实现细节。

答案 2 :(得分:17)

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

事件是一个更高级别的抽象,它包含委托的概念以及为这些委托订阅和取消订阅方法的方法。

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

答案 3 :(得分:8)

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

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

答案 4 :(得分: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");
        }
    }
}

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

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

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

    Console.ReadLine();
}

那么什么时候我们明确地实现委托?在he said

时,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.");
        }
    }
}

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

详细了解When to Use Delegates Instead of Interfaces

答案 5 :(得分:1)

这是一篇非常好的文章。

http://www.akadia.com/services/dotnet_delegates_and_events.html

基本上,事件提供了紧密耦合的发布订阅范例,而代理提供了更松散耦合的设计。

但事件使用起来更简单,更直接。

答案 6 :(得分:0)

代理只是一个函数指针,在函数中异步调用但是事件只是通知。例如,单击按钮是一个事件,因此您需要订阅按钮的单击事件等。