C#中委托与事件的核心区别及代码实现

宋时安
宋时安
发布时间:2026-10-14 | 4人浏览过
原创

本文详细对比了C#中委托与事件的异同,涵盖从委托类的实例化到事件的多路广播机制。通过剖析代码执行流程、参数传递以及EventHandler标准模式,揭示两者在封装性与调用方式上的核心差异。

结果或目标:理清委托与事件的角色

C#开发中经常混淆委托(Delegate)与事件(Event)。简而言之,**委托是一种类型**(类似于类),它定义了一类方法的签名;而**事件是一种成员**,它基于委托类型,并对外提供受控的访问权限(只能+=添加订阅,不能直接=赋值或调用)。本文将分别演示如何通过这两种机制调用方法,并解析其内部行为。

准备条件:了解CLR对委托的处理

在编写代码前,需明确以下事实:

  • 委托(Delegate)在运行时是一个类。
  • 该类的构造函数接受一个方法作为参数。
  • 委托对象包含一个Invoke实例方法,用于同步调用所绑定的方法列表。

真实操作顺序

第1步:通过委托执行方法

目的:展示委托作为类的基本用法,包括声明、实例化和调用。

步骤详解:

  1. 声明委托类型:定义DoSth委托,指定参数为string,返回值为void。
  2. 创建委托实例:使用new DoSth(Print)将Print方法绑定到委托变量d上。
  3. 执行调用:可以使用d.Invoke(str)显式调用,也可以直接使用d(str)隐式调用。
class Program
{
    static void Main(string[] args)
    {
        Example example = new Example();
        example.Go();
        Console.ReadKey();
    }
}
public class Example
{
    // 1. 声明委托
    public delegate void DoSth(string str);
    
    internal void Go()
    {
        // 2. 实例化委托,指向Print方法
        DoSth d = new DoSth(Print);
        string str = "Hello,World";
        
        // 3. 执行委托,两种写法等价
        d.Invoke(str); 
        // d(str); 
    }
    
    void Print(string str)
    {
        Console.WriteLine(str);
    }
}

关键点:当委托签名包含object sender, EventArgs e时,通常遵循.NET事件命名规范。sender表示触发动作的对象,e携带相关数据。

第2步:通过事件执行方法(标准模型)

目的:演示如何使用event关键字限制外部对委托的直接调用,仅允许订阅和取消订阅。

步骤详解:

  1. 声明事件:使用public event DoSth myDoSth;声明,其中DoSth是之前的委托类型。
  2. 注册委托:使用+=运算符将方法或委托实例添加到事件列表中。这不仅支持单个方法,还支持多播(Multiple Casting)。
  3. 触发事件:在类内部调用myDoSth(sender, e)。
public class Example
{
    public delegate void DoSth(object sender, EventArgs e);
    public event DoSth myDoSth;

    internal void Go()
    {
        object sender = 10;
        EventArgs e = new EventArgs();
        
        // 注册多个方法
        myDoSth += Print;
        myDoSth += Say;
        
        // 触发事件
        myDoSth(sender, e);
    }
    
    void Print(object sender, EventArgs e) { Console.WriteLine("Print: " + sender); }
    void Say(object sender, EventArgs e) { Console.WriteLine("Say: " + sender); }
}

完成状态判断:程序输出应同时显示“Print”和“Say”的信息,表明事件成功触发了所有注册的监听者。

第3步:使用内置EventHandler简化开发

目的:避免自定义委托签名,使用框架提供的通用模式。

操作说明:

.NET框架定义了通用的EventHandler<TEventArgs>委托(旧版为EventHandler)。其签名为void Handler(object sender, TEventArgs e)。使用它可以减少样板代码。

public class Example
{
    // 使用系统内置的EventHandler,无需自行定义DoSth
    public event EventHandler myEvent;

    internal void Go()
    {
        object sender = 10;
        EventArgs e = new EventArgs();
        
        myEvent += Print;
        myEvent += Say;
        
        myEvent(sender, e);
    }
    
    void Print(object sender, EventArgs e) { Console.WriteLine("Print: " + sender); }
    void Say(object sender, EventArgs e) { Console.WriteLine("Say: " + sender); }
}

原文有依据的排错与注意事项

  • 安全性差异:如果在类外部尝试example.myDoSth = null会编译错误,因为事件只暴露了+/-运算符。这防止了外部意外清空所有事件监听器。
  • 调用位置:事件只能在声明它的类内部被调用。如果需要在其他地方触发通知,应提供一个公共方法来封装事件调用。
  • 空引用检查:在多线程环境下或移除所有订阅后,myEvent(sender, e)可能为空。推荐写法:myEvent?.Invoke(sender, e);或旧式的if (myEvent != null) myEvent(...)。

简要总结

委托是方法的容器,本质是类;事件是基于委托的包装,提供受限的访问控制。两者结合+=和-=构成了C#强大的发布-订阅(Pub-Sub)模型。对于标准UI事件或业务逻辑通知,推荐使用EventHandler以保持一致性。以上就是C#中委托和事件的区别实例解析的详细内容,更多关于C#高级特性与内存管理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表