C#中委托与事件的核心区别及代码实现
本文详细对比了C#中委托与事件的异同,涵盖从委托类的实例化到事件的多路广播机制。通过剖析代码执行流程、参数传递以及EventHandler标准模式,揭示两者在封装性与调用方式上的核心差异。
结果或目标:理清委托与事件的角色
C#开发中经常混淆委托(Delegate)与事件(Event)。简而言之,**委托是一种类型**(类似于类),它定义了一类方法的签名;而**事件是一种成员**,它基于委托类型,并对外提供受控的访问权限(只能+=添加订阅,不能直接=赋值或调用)。本文将分别演示如何通过这两种机制调用方法,并解析其内部行为。
准备条件:了解CLR对委托的处理
在编写代码前,需明确以下事实:
- 委托(Delegate)在运行时是一个类。
- 该类的构造函数接受一个方法作为参数。
- 委托对象包含一个
Invoke实例方法,用于同步调用所绑定的方法列表。
真实操作顺序
第1步:通过委托执行方法
目的:展示委托作为类的基本用法,包括声明、实例化和调用。
步骤详解:
- 声明委托类型:定义
DoSth委托,指定参数为string,返回值为void。 - 创建委托实例:使用
new DoSth(Print)将Print方法绑定到委托变量d上。 - 执行调用:可以使用
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关键字限制外部对委托的直接调用,仅允许订阅和取消订阅。
步骤详解:
- 声明事件:使用
public event DoSth myDoSth;声明,其中DoSth是之前的委托类型。 - 注册委托:使用
+=运算符将方法或委托实例添加到事件列表中。这不仅支持单个方法,还支持多播(Multiple Casting)。 - 触发事件:在类内部调用
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#高级特性与内存管理的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









