MST
星途 面试题库

面试题:C# 中委托与事件的联系与区别

请详细阐述 C# 中委托(Delegate)和事件(Event)的概念,说明它们之间有什么联系,以及存在哪些区别。并举例说明如何在实际代码中正确定义和使用委托与事件。
33.5万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试

C# 中委托(Delegate)和事件(Event)的概念

  1. 委托(Delegate)
    • 委托是一种类型,它定义了方法的签名,允许将方法作为参数传递给其他方法,也可以将多个方法添加到一个委托实例中,形成方法调用列表。可以把委托看作是一个函数指针的类型安全版本。例如,有一个委托 public delegate void MyDelegate(int num);,它定义了一个接受一个 int 类型参数且无返回值的方法签名。任何符合这个签名的方法,如 public void PrintNumber(int num) { Console.WriteLine(num); } 都可以添加到这个委托的实例中。
  2. 事件(Event)
    • 事件是一种特殊的委托实例,它基于委托来实现发布 - 订阅模式。事件的发布者(拥有事件的类)可以通知多个订阅者(注册了事件处理方法的对象)发生了某个特定的事情。例如,在一个图形化界面程序中,按钮点击事件就是一个事件,按钮类是发布者,当按钮被点击时,会通知所有注册了该点击事件处理方法的对象进行相应处理。

委托和事件的联系

  1. 基于委托实现:事件本质上是基于委托实现的。事件实际上是一个受限制的委托实例,它对委托的使用进行了一些封装和约束。
  2. 订阅机制:都使用类似的订阅机制,即可以向委托或事件中添加方法(订阅),在合适的时机调用这些方法(触发委托或事件)。

委托和事件的区别

  1. 访问修饰符
    • 委托可以有各种访问修饰符,如 publicprivate 等,它可以在程序的任何地方被实例化和调用。
    • 事件通常使用 public 修饰符,但它的访问受到限制。事件只能在声明它的类内部触发,外部只能进行订阅和取消订阅操作。例如,在类 A 中声明了一个事件 public event MyDelegate MyEvent;,在类 A 外部不能直接调用 MyEvent() 来触发事件,只能使用 AInstance.MyEvent += new MyDelegate(SomeMethod); 来订阅事件。
  2. 功能侧重点
    • 委托更侧重于方法的封装和传递,主要用于将方法作为参数传递给其他方法,或者实现回调机制。比如在 ThreadPool.QueueUserWorkItem(new WaitCallback(MyMethod)); 中,WaitCallback 就是一个委托,将 MyMethod 方法传递给线程池的工作项。
    • 事件侧重于实现发布 - 订阅模式,用于在对象间进行事件通知。例如,在一个游戏中,角色死亡事件会通知游戏系统进行相关处理,如更新分数、记录日志等。
  3. 内存管理
    • 委托如果使用不当,可能会导致内存泄漏。例如,当一个委托实例持有对某个对象的强引用,而这个对象本应被释放,但由于委托的引用而无法释放时,就会发生内存泄漏。
    • 事件由于其访问限制,在一定程度上减少了这种风险,因为外部不能随意触发事件,只能进行订阅和取消订阅操作,更有利于内存管理。

实际代码中定义和使用委托与事件的示例

  1. 委托示例
using System;

// 定义委托
public delegate void MyDelegate(int num);

class Program
{
    // 定义符合委托签名的方法
    public static void PrintNumber(int num)
    {
        Console.WriteLine(num);
    }

    // 方法接受委托作为参数
    public static void DoSomething(MyDelegate del, int num)
    {
        del(num);
    }

    static void Main()
    {
        MyDelegate myDel = new MyDelegate(PrintNumber);
        DoSomething(myDel, 10);
    }
}
  1. 事件示例
using System;

// 定义委托
public delegate void MyEventHandler(object sender, EventArgs e);

class Publisher
{
    // 定义事件
    public event MyEventHandler MyEvent;

    public void RaiseEvent()
    {
        if (MyEvent != null)
        {
            MyEvent(this, EventArgs.Empty);
        }
    }
}

class Subscriber
{
    public void HandleEvent(object sender, EventArgs e)
    {
        Console.WriteLine("Event received by subscriber.");
    }
}

class Program
{
    static void Main()
    {
        Publisher publisher = new Publisher();
        Subscriber subscriber = new Subscriber();

        publisher.MyEvent += subscriber.HandleEvent;

        publisher.RaiseEvent();
    }
}