一、事件核心基础概念
1、本质
事件基于委托实现,是被 event 关键字封装安全版委托,遵循【发布 - 订阅模式】
- 发布者(发布类) :定义事件、满足条件主动触发调用事件(示例
Calc类) - 订阅者 :外部通过
+=绑定处理方法,等待事件触发自动执行(Main 里绑定 F1)
2、语法两步走
-
先有委托类型 (自定义委托 / 系统
EventHandler) -
event + 委托类型 + 事件名定义事件//格式
public event 委托类型 事件名称;
3、事件三大操作
- 订阅绑定 :外部只能用
事件 += 方法,禁止直接 = 赋值(事件封装保护,和多播委托区别) - 取消订阅 :
事件 -= 方法 - 触发调用 :只能在发布类内部
事件?.Invoke(实参),类外不能直接调用事件
关键区别:委托变量外面可以
del = 方法、del();事件外部不能赋值、不能直接调用,只能+=/-=。
二、案例 1:系统内置 EventHandler 事件
internal class Program
{
//内置事件委托:EventHandler固定签名 void 方法(object sender, EventArgs e)
public static event EventHandler MyClick;
static void Main(string[] args)
{
//订阅:+=绑定普通方法、Lambda
MyClick += new EventHandler(F1);
MyClick += (sender, e) =>
{
Console.WriteLine("lambda表达式");
};
//本类内部触发事件
MyClick?.Invoke(null, null);
}
//匹配EventHandler格式:object发送者,EventArgs事件参数
static void F1(object sender, EventArgs s)
{
Console.WriteLine("F1方法");
}
}
sender:触发事件的对象EventArgs:事件附带参数(无参时传 null)
三、案例 2:自定义委托实现事件(计算器 Calc 示例,重点)
1. 发布类 Calc(定义委托 + 事件,满足条件触发事件)
public class Calc
{
//①自定义委托:规定事件处理方法格式(三个int参数无返回)
public delegate void AddDel(int a, int b, int sum);
//②用委托定义事件
public event AddDel Finished;
public void Add(int a, int b)
{
int sum = a + b;
//③满足计算完成,在类内部触发事件,空安全调用
Finished?.Invoke(a, b, sum);
}
}
2. 订阅端 Main(绑定事件,不控制触发,只写处理逻辑)
internal class Program
{
static void Main(string[] args)
{
Calc c = new Calc();
//订阅事件:+=绑定处理方法
c.Finished += F1;
//调用Add方法,方法内部自动触发Finished事件 → 执行F1
c.Add(10, 20);
c.Add(30, 20);
}
//方法签名和委托AddDel完全一致
static void F1(int a, int b, int c)
{
Console.WriteLine($"a的值为{a},b的值为{b},c的值为{c}");
}
}
运行输出
a的值为10,b的值为20,c的值为30
a的值为30,b的值为20,c的值为50
四、事件 VS 委托(必考区分)
表格
| 操作 | 委托 (delegate 变量) | 事件 (event) |
|---|---|---|
| 外部赋值 | del = 方法 允许 |
❌禁止直接 = |
| 增减绑定 | del += / -= |
event += / -=(仅允许) |
| 外部调用 | del.Invoke() 允许 |
❌只能在定义类内部调用 |
event 就是给委托加了访问保护,防止外部随意清空所有绑定(
委托=null清空所有方法,事件做不到)。
五、两种事件写法总结
- 通用无参事件:用系统自带
event EventHandler 事件名,不用自己定义委托 - 需要自定义参数:先自定义委托 → event 委托 事件名(计算器案例)
六、背诵口诀
事件依托委托造,event来做防护罩;
发布定义事件位,订阅只用加等号;
外部不能直接调,内部Invoke来引爆;
内置Handler两参数,自定义委托参数随便套。