C# 方法、委托与事件 一、今天要讲什么今天主要讲 3 个 C# 中非常重要的概念方法Method委托Delegate事件Event它们之间的关系可以简单理解为方法 ↓ 委托 ↓ 事件一句话理解方法负责干活委托负责传递方法事件负责通知别人。二、什么是方法2.1 方法是什么方法就是一段可以被重复调用的代码。例如void SayHello() { Console.WriteLine(你好); }调用SayHello();运行结果你好我们可以把方法理解成一个“功能”。例如SayHello() → 打招呼 Add() → 计算 Connect() → 连接设备 Capture() → 拍照 SaveImage() → 保存图片在实际的上位机项目中我们会大量使用方法。三、方法的基本结构一个方法通常包含访问修饰符 返回值类型 方法名(参数) { // 方法里面的代码 }例如public int Add(int a, int b) { return a b; }调用int result Add(10, 20); ​ Console.WriteLine(result);结果303.1 参数是什么参数就是调用方法的时候传进去的数据。void SayHello(string name) { Console.WriteLine(你好 name); }调用SayHello(小明);这里name就是参数。四、为什么需要委托先看一个问题。假设我们有两个方法void SayHello() { Console.WriteLine(你好); } void SayBye() { Console.WriteLine(再见); }我们可以直接调用SayHello(); SayBye();但是如果我们希望把一个方法当成“数据”传给另一个方法。普通方法就不方便了。这时候就需要委托 Delegate五、什么是委托委托可以简单理解成委托就是一个可以保存“方法”的变量。例如Action action;然后action SayHello;现在action ↓ SayHello()调用action();实际上执行的就是SayHello();六、最简单的委托例子using System; class Program { static void SayHello() { Console.WriteLine(你好); } static void Main() { Action action SayHello; action(); } }运行你好七、Action 是什么Action是 C# 已经帮我们定义好的委托。例如Action表示没有参数 没有返回值例如void SayHello() { Console.WriteLine(你好); }可以Action action SayHello;7.1 Action 有参数例如Actionstring action;表示有一个 string 参数 没有返回值所以void SayHello(string name) { Console.WriteLine(你好 name); }可以Actionstring action SayHello; action(小明);7.2 Action 多个参数例如Actionstring, int表示string int 没有返回值例如void Test(string name, int age) { Console.WriteLine(name); Console.WriteLine(age); }可以Actionstring, int action Test; action(小明, 20);八、Func 是什么除了ActionC# 还有Func它和 Action 最大的区别Func 有返回值。例如int Add(int a, int b) { return a b; }可以Funcint, int, int func Add; int result func(10, 20);结果30这里Funcint, int, int最后一个int是返回值。所以Funcint, int, int ↑ ↑ ↑ 参数 参数 返回值九、为什么委托很重要委托最大的意义之一可以把“具体执行什么”交给别人决定。例如void Test(Action action) { Console.WriteLine(开始执行); action(); Console.WriteLine(执行结束); }调用Test(SayHello);也可以Test(SayBye);这样Test()不需要知道具体执行的是SayHello还是SayBye它只负责调用传进来的方法。十、什么是事件事件event事件本质上是建立在委托基础上的。可以简单理解事件就是一种“通知机制”。例如相机拍照完成 ↓ 通知程序 ↓ 保存图片 ↓ 更新界面或者TCP收到数据 ↓ 触发事件 ↓ 通知Form1 ↓ 显示数据十一、生活中的事件例子可以把事件理解成学校 ↓ 下课铃响 ↓ 通知学生老师不需要一个个告诉学生张三下课 李四下课 王五下课只需要铃声响订阅了这个铃声的人就知道下课了C# 的事件也是类似的。十二、最简单的事件先定义一个事件public event Actionstring DataReceived;这里event ↓ 事件 Actionstring ↓ 事件发生时需要传递一个 string触发事件DataReceived?.Invoke(收到数据);这里?.表示如果这个事件有人订阅就调用它。十三、事件的完整例子定义一个设备类class Device { public event Actionstring DataReceived; public void ReceiveData() { string data Hello; DataReceived?.Invoke(data); } }然后 Form 中Device device new Device(); device.DataReceived Device_DataReceived;事件处理方法private void Device_DataReceived(string data) { Console.WriteLine(收到 data); }调用device.ReceiveData();最终Device ↓ ReceiveData() ↓ DataReceived事件 ↓ Device_DataReceived() ↓ 收到Hello十四、 是什么意思订阅事件device.DataReceived Device_DataReceived;可以理解为当 DataReceived 事件发生的时候调用Device_DataReceived。取消订阅device.DataReceived - Device_DataReceived;所以 ↓ 订阅 - ↓ 取消订阅十五、委托和事件有什么区别这是非常容易被问到的问题。委托委托Actionstring action;可以action Test;可以直接调用action(Hello);事件事件public event Actionstring DataReceived;外部通常只能DataReceived Test;或者DataReceived - Test;外部不能随便DataReceived(Hello);真正触发事件通常由事件所属的类自己完成DataReceived?.Invoke(Hello);所以可以简单理解委托更自由事件更强调“只能订阅和取消订阅”。十六、为什么实际项目大量使用事件因为很多设备都是设备发生事情 ↓ 程序需要知道 ↓ 通知程序例如串口收到数据 TCP收到数据 相机拍照完成 PLC状态发生变化 定时器到时间 按钮被点击这些都非常适合事件。十七、结合 TCP 项目理解例如我们以前写 TCP 的时候public event Actionstring DataReceived;TCP 收到数据string data Hello; DataReceived?.Invoke(data);Form1 订阅_client.DataReceived Client_DataReceived;然后private void Client_DataReceived(string data) { richTextBox1.AppendText(data); }整个过程TCP客户端 ↓ 收到数据 ↓ DataReceived事件 ↓ Form1 ↓ 显示数据这样 TCP 类就不需要知道“收到数据以后到底应该显示在哪里”TCP 类只需要“我收到数据了我通知你。”这就是事件解耦的一种体现。十八、结合串口项目理解串口同样可以public event Actionbyte[] DataReceived;收到数据byte[] data serialPort.Read(...); DataReceived?.Invoke(data);其他类订阅serial.DataReceived Serial_DataReceived;这样串口 ↓ 收到数据 ↓ 事件 ↓ 业务代码 ↓ 解析数据十九、结合视觉项目理解在视觉项目中也可以使用事件。例如public event ActionICogImage ImageGrabbed;相机拍到图片ImageGrabbed?.Invoke(image);Form_camera.ImageGrabbed Camera_ImageGrabbed;然后private void Camera_ImageGrabbed(ICogImage image) { cogRecordDisplay1.Image image; }流程康耐视相机 ↓ 拍照 ↓ 得到 ICogImage ↓ ImageGrabbed事件 ↓ Form1 ↓ 显示图像二十、方法、委托、事件的关系可以画成方法 │ ↓ 可以被委托保存 │ ↓ 委托 │ ↓ 可以建立事件 │ ↓ 事件 │ ↓ 通知其他对象二十一、三者最简单的理解方法我自己干活。void SayHello() { Console.WriteLine(你好); }委托我把“干什么”交给别人。Action action SayHello; action();事件我干完了/发生事情了我通知你。public event Actionstring DataReceived;发生事情DataReceived?.Invoke(收到数据);二十二、一个完整的小例子using System; class Device { // 定义事件 public event Actionstring DataReceived; // 模拟设备接收数据 public void Receive() { string data 设备发送的数据; // 触发事件 DataReceived?.Invoke(data); } } class Program { static void Main() { Device device new Device(); // 订阅事件 device.DataReceived Device_DataReceived; // 模拟接收数据 device.Receive(); } static void Device_DataReceived(string data) { Console.WriteLine(收到 data); } }运行收到设备发送的数据二十三、几个小问题问题1什么是委托可以回答委托是 C# 中用于封装方法的类型可以把方法作为参数传递也可以保存方法的引用。问题2什么是事件可以回答事件是建立在委托基础上的一种通知机制常用于一个对象发生某件事情以后通知其他对象。问题3委托和事件有什么区别可以回答委托可以直接赋值和调用而事件主要用于订阅和取消订阅事件的触发通常由事件所属的类内部完成。问题4Action 和 Func 有什么区别可以回答Action 表示没有返回值的委托Func 表示有返回值的委托Func 的最后一个泛型参数表示返回值类型。问题5?.Invoke()是什么意思例如DataReceived?.Invoke(data);意思是如果DataReceived当前有人订阅就调用这个事件如果没人订阅就什么也不做避免空引用异常。二十四、最后总结今天主要学习方法 ↓ 完成具体功能 委托 ↓ 保存/传递方法 事件 ↓ 发生事情后通知其他对象最重要的一句话方法负责干活委托负责传递方法事件负责通知别人。在实际的 C# 上位机开发中TCP收到数据 ↓ 事件 串口收到数据 ↓ 事件 相机拍照完成 ↓ 事件 PLC状态变化 ↓ 事件所以委托和事件是 C# 做设备通信、UI程序、上位机程序时非常重要的基础知识。二十五、推荐学习顺序如果继续深入 C#可以按照变量 ↓ 条件判断 ↓ 循环 ↓ 方法 ↓ 类和对象 ↓ 继承 ↓ 接口 ↓ 委托 ↓ 事件 ↓ 泛型 ↓ LINQ ↓ Task / async / await ↓ 多线程 ↓ 反射 ↓ 依赖注入对于上位机开发建议重点掌握C# ↓ 面向对象 ↓ 委托 / 事件 ↓ 异步 / Task ↓ TCP / 串口 ↓ 数据库 ↓ WinForms / WPF ↓ VisionPro ↓ PLC / Modbus