上一篇我们完成了C#全套知识点综合实战项目从零搭建分层架构的权限管理系统完美整合了面向对象、LINQ、IO、异常、反射、AOP等所有核心知识点正式完成了C#基础与高阶语法的落地实战。到目前为止我们写的所有代码都是顺序执行、主动调用程序写死执行顺序主动调用方法逻辑高度固化。但在真实开发中回调通知、异步执行、触发响应、解耦调用是刚需按钮点击自动触发方法、任务完成自动回调、异步操作结束通知、模块之间解耦通信……实现这一切的底层核心就是本篇两大重难点委托Delegate与事件Event。委托和事件是C#进阶的分水岭知识点是异步编程、多线程、Winform/WPF界面开发、框架回调、模块解耦的绝对基石。零基础手把手通俗拆解告别死记硬背彻底吃透核心原理与实战用法一、委托核心认知到底什么是委托1. 通俗白话理解委托正常调用直接调用方法写死调用关系谁调用、调用哪个方法固定不变。委托调用方法的容器、方法的替身。可以把方法赋值给委托变量通过委托间接调用方法运行时动态切换执行的方法。一句话总结委托就是用来存储、传递、调用方法的特殊类型。如果没有委托方法只能固定调用有了委托可以动态绑定方法、动态切换逻辑、实现回调执行。2. 委托的核心价值方法解耦调用方不用绑定具体方法通过委托统一调用彻底解耦动态调用运行时动态替换、新增、移除执行的方法灵活度拉满回调核心所有回调逻辑、完成通知、事件触发全部基于委托实现异步底层Task、多线程、异步编程的底层全部依赖委托机制二、自定义委托语法详解零基础实战1. 委托定义语法委托的定义和方法声明相似只需前方加delegate关键字核心规则委托的返回值、参数列表必须和绑定的方法完全一致。// 委托定义语法// 修饰符 delegate 返回值类型 委托名(参数列表);publicdelegatevoidMyDelegate(stringmsg);解读定义了一个名为 MyDelegate 的委托只能绑定无返回值、单个string参数的方法。2. 委托基础实战绑定方法调用方法我们通过最简单案例看懂委托的完整执行流程定义委托、编写适配方法、绑定委托、委托调用。usingSystem;namespaceDelegateDemo{// 1. 定义委托匹配无返回值、string参数publicdelegatevoidShowMsgDelegate(stringmsg);classProgram{staticvoidMain(string[]args){// 3. 实例化委托、绑定适配的方法ShowMsgDelegatedelShowMessage;// 4. 通过委托调用方法del(Hello 委托);}// 2. 编写和委托签名一致的方法publicstaticvoidShowMessage(stringmsg){Console.WriteLine(委托执行msg);}}}运行结果委托执行Hello 委托看似多此一举但核心优势是后续可以随意替换绑定的方法不用修改调用逻辑。3. 委托多播一个委托绑定多个方法委托支持多播多绑定一个委托变量可以绑定多个方法调用时依次执行所有绑定方法是事件多触发的底层原理。// 定义委托publicdelegatevoidOperateDelegate();classProgram{staticvoidMain(string[]args){OperateDelegatedelnull;// 绑定多个方法delAddOperate;delEditOperate;delDeleteOperate;// 委托调用依次执行所有方法del();// 移除指定方法del-EditOperate;Console.WriteLine(移除编辑方法后);del();}publicstaticvoidAddOperate(){Console.WriteLine(执行新增操作);}publicstaticvoidEditOperate(){Console.WriteLine(执行编辑操作);}publicstaticvoidDeleteOperate(){Console.WriteLine(执行删除操作);}}核心符号 绑定方法- 移除方法这是委托多播的核心写法。三、系统内置委托不用重复定义直接开箱即用开发中90%场景无需自定义委托C# 内置了三种万能委托覆盖所有方法场景极简高效是项目开发首选。三大内置委托对照表内置委托作用适用场景Action无参数、无返回值纯执行逻辑无需入参、无需返回值Action有参数、无返回值需要传入参数仅执行操作Func有返回值可带参数需要执行后返回结果的逻辑1. Action 无参无返回值ActionactionSayHello;action();publicstaticvoidSayHello(){Console.WriteLine(Hello Action);}2. Action 有参无返回值ActionstringactionShowMsg;action(传入参数测试);publicstaticvoidShowMsg(stringmsg){Console.WriteLine(参数内容msg);}3. Func 有返回值委托核心常用Func 最后一个泛型参数为返回值类型前面全部是参数类型。// 传入int返回intFuncint,intfuncAddNum;intresfunc(10);Console.WriteLine(计算结果res);publicstaticintAddNum(intnum){returnnum100;}开发规范优先使用系统内置 Action/Func仅特殊场景自定义委托。四、匿名方法与Lambda表达式委托极简写法委托不用每次都单独定义方法搭配匿名方法、Lambda表达式可以直接内联写逻辑代码极度精简是现代C#开发主流写法。1. 匿名方法绑定委托Actionactiondelegate(){Console.WriteLine(匿名方法执行逻辑);};action();2. Lambda表达式终极精简写法Lambda 是委托的语法糖极简优雅项目中最常用// 无参LambdaActionaction()Console.WriteLine(Lambda无参执行);// 有参LambdaActionintprintNumnConsole.WriteLine(数字n);// 有参有返回值LambdaFuncint,intcalcxx*2;Console.WriteLine(calc(20));之前学的LINQ查询底层全部是基于委托Lambda实现五、事件Event委托的安全升级版1. 为什么需要事件委托存在一个致命缺陷外部可以直接赋值覆盖所有绑定方法极不安全。比如del 新方法; 会直接清空之前所有 绑定的逻辑造成业务bug。而事件event是专门为了解决委托安全问题诞生的是带访问限制的特殊委托。2. 事件与委托的核心区别权限限制事件只能在类内部触发外部只能订阅、取消订阅-不能直接赋值、不能主动触发安全性高杜绝外部覆盖逻辑、非法调用适合模块间通知语义不同委托是数据类型、用于传参调用事件是消息通知、用于触发回调3. 事件完整实战模拟任务完成通知场景后台任务执行完成自动触发事件通知所有订阅者执行回调逻辑。usingSystem;namespaceEventDemo{// 1. 定义委托规范事件签名publicdelegatevoidTaskFinishDelegate(stringtaskName);classTaskManager{// 2. 定义事件基于委托publiceventTaskFinishDelegateTaskFinishEvent;// 执行任务publicvoidRunTask(stringtaskName){Console.WriteLine($正在执行任务{taskName});// 任务执行完成触发事件通知所有订阅者TaskFinishEvent?.Invoke(taskName);}}classProgram{staticvoidMain(string[]args){TaskManagertaskManagernewTaskManager();// 订阅事件taskManager.TaskFinishEventLogFinish;taskManager.TaskFinishEventShowTip;// 执行任务自动触发所有订阅方法taskManager.RunTask(数据同步任务);}// 订阅方法1记录日志publicstaticvoidLogFinish(stringtaskName){Console.WriteLine($日志记录{taskName}执行完成);}// 订阅方法2弹窗提示publicstaticvoidShowTip(stringtaskName){Console.WriteLine($系统提示{taskName}已结束);}}}运行效果任务执行完成后自动依次执行日志记录、弹窗提示逻辑完全解耦六、委托事件核心实战模拟按钮点击事件我们日常Winform、WPF的按钮点击Button.Click本质就是事件机制手写模拟底层原理usingSystem;// 定义点击委托publicdelegatevoidClickDelegate();// 模拟按钮类publicclassButton{// 定义点击事件publiceventClickDelegateClick;// 模拟按钮被点击publicvoidOnClick(){Console.WriteLine(按钮被点击);// 触发事件Click?.Invoke();}}classProgram{staticvoidMain(){ButtonbtnnewButton();// 订阅点击事件btn.ClickBtn_Click;// 模拟用户点击按钮btn.OnClick();}// 点击回调逻辑privatestaticvoidBtn_Click(){Console.WriteLine(执行按钮点击业务逻辑提交表单);}}这就是所有界面事件的底层原理彻底看懂UI事件触发机制七、委托与事件核心区别总结面试必背定义方式委托用delegate事件用event委托访问权限委托公开可任意赋值、调用事件外部仅可订阅/取消安全可控使用场景委托用于方法传递、动态调用、参数封装事件用于消息通知、回调触发、模块解耦安全性委托不安全可被覆盖事件安全杜绝非法篡改八、新手高频易错坑点必避签名不匹配委托和绑定方法的返回值、参数必须完全一致否则报错空委托调用报错调用前必须判断非空推荐委托?.Invoke()极简判空写法混淆委托和事件需要动态调用用委托需要消息通知用事件滥用赋值符号多播绑定必须用 禁止直接 赋值会覆盖原有逻辑事件外部触发事件只能在定义类内部触发外部无法直接Invoke九、全文核心总结委托本质存储方法、传递方法的特殊类型实现动态调用、多播执行内置委托Action无返回值、Func有返回值覆盖99%开发场景精简写法匿名方法、Lambda表达式是委托的语法糖极简开发事件本质委托的安全升级版用于模块通知、回调触发、界面事件核心价值彻底解耦代码、实现回调机制是异步、多线程、UI编程的底层基石。下期预告下一篇我们将基于委托与事件精讲C# 异步编程与多线程彻底解决程序卡顿、耗时操作阻塞问题解锁高性能编程核心能力
C#零基础通关第十七篇:吃透委托与事件,彻底搞懂回调编程、异步底层、解耦核心
上一篇我们完成了C#全套知识点综合实战项目从零搭建分层架构的权限管理系统完美整合了面向对象、LINQ、IO、异常、反射、AOP等所有核心知识点正式完成了C#基础与高阶语法的落地实战。到目前为止我们写的所有代码都是顺序执行、主动调用程序写死执行顺序主动调用方法逻辑高度固化。但在真实开发中回调通知、异步执行、触发响应、解耦调用是刚需按钮点击自动触发方法、任务完成自动回调、异步操作结束通知、模块之间解耦通信……实现这一切的底层核心就是本篇两大重难点委托Delegate与事件Event。委托和事件是C#进阶的分水岭知识点是异步编程、多线程、Winform/WPF界面开发、框架回调、模块解耦的绝对基石。零基础手把手通俗拆解告别死记硬背彻底吃透核心原理与实战用法一、委托核心认知到底什么是委托1. 通俗白话理解委托正常调用直接调用方法写死调用关系谁调用、调用哪个方法固定不变。委托调用方法的容器、方法的替身。可以把方法赋值给委托变量通过委托间接调用方法运行时动态切换执行的方法。一句话总结委托就是用来存储、传递、调用方法的特殊类型。如果没有委托方法只能固定调用有了委托可以动态绑定方法、动态切换逻辑、实现回调执行。2. 委托的核心价值方法解耦调用方不用绑定具体方法通过委托统一调用彻底解耦动态调用运行时动态替换、新增、移除执行的方法灵活度拉满回调核心所有回调逻辑、完成通知、事件触发全部基于委托实现异步底层Task、多线程、异步编程的底层全部依赖委托机制二、自定义委托语法详解零基础实战1. 委托定义语法委托的定义和方法声明相似只需前方加delegate关键字核心规则委托的返回值、参数列表必须和绑定的方法完全一致。// 委托定义语法// 修饰符 delegate 返回值类型 委托名(参数列表);publicdelegatevoidMyDelegate(stringmsg);解读定义了一个名为 MyDelegate 的委托只能绑定无返回值、单个string参数的方法。2. 委托基础实战绑定方法调用方法我们通过最简单案例看懂委托的完整执行流程定义委托、编写适配方法、绑定委托、委托调用。usingSystem;namespaceDelegateDemo{// 1. 定义委托匹配无返回值、string参数publicdelegatevoidShowMsgDelegate(stringmsg);classProgram{staticvoidMain(string[]args){// 3. 实例化委托、绑定适配的方法ShowMsgDelegatedelShowMessage;// 4. 通过委托调用方法del(Hello 委托);}// 2. 编写和委托签名一致的方法publicstaticvoidShowMessage(stringmsg){Console.WriteLine(委托执行msg);}}}运行结果委托执行Hello 委托看似多此一举但核心优势是后续可以随意替换绑定的方法不用修改调用逻辑。3. 委托多播一个委托绑定多个方法委托支持多播多绑定一个委托变量可以绑定多个方法调用时依次执行所有绑定方法是事件多触发的底层原理。// 定义委托publicdelegatevoidOperateDelegate();classProgram{staticvoidMain(string[]args){OperateDelegatedelnull;// 绑定多个方法delAddOperate;delEditOperate;delDeleteOperate;// 委托调用依次执行所有方法del();// 移除指定方法del-EditOperate;Console.WriteLine(移除编辑方法后);del();}publicstaticvoidAddOperate(){Console.WriteLine(执行新增操作);}publicstaticvoidEditOperate(){Console.WriteLine(执行编辑操作);}publicstaticvoidDeleteOperate(){Console.WriteLine(执行删除操作);}}核心符号 绑定方法- 移除方法这是委托多播的核心写法。三、系统内置委托不用重复定义直接开箱即用开发中90%场景无需自定义委托C# 内置了三种万能委托覆盖所有方法场景极简高效是项目开发首选。三大内置委托对照表内置委托作用适用场景Action无参数、无返回值纯执行逻辑无需入参、无需返回值Action有参数、无返回值需要传入参数仅执行操作Func有返回值可带参数需要执行后返回结果的逻辑1. Action 无参无返回值ActionactionSayHello;action();publicstaticvoidSayHello(){Console.WriteLine(Hello Action);}2. Action 有参无返回值ActionstringactionShowMsg;action(传入参数测试);publicstaticvoidShowMsg(stringmsg){Console.WriteLine(参数内容msg);}3. Func 有返回值委托核心常用Func 最后一个泛型参数为返回值类型前面全部是参数类型。// 传入int返回intFuncint,intfuncAddNum;intresfunc(10);Console.WriteLine(计算结果res);publicstaticintAddNum(intnum){returnnum100;}开发规范优先使用系统内置 Action/Func仅特殊场景自定义委托。四、匿名方法与Lambda表达式委托极简写法委托不用每次都单独定义方法搭配匿名方法、Lambda表达式可以直接内联写逻辑代码极度精简是现代C#开发主流写法。1. 匿名方法绑定委托Actionactiondelegate(){Console.WriteLine(匿名方法执行逻辑);};action();2. Lambda表达式终极精简写法Lambda 是委托的语法糖极简优雅项目中最常用// 无参LambdaActionaction()Console.WriteLine(Lambda无参执行);// 有参LambdaActionintprintNumnConsole.WriteLine(数字n);// 有参有返回值LambdaFuncint,intcalcxx*2;Console.WriteLine(calc(20));之前学的LINQ查询底层全部是基于委托Lambda实现五、事件Event委托的安全升级版1. 为什么需要事件委托存在一个致命缺陷外部可以直接赋值覆盖所有绑定方法极不安全。比如del 新方法; 会直接清空之前所有 绑定的逻辑造成业务bug。而事件event是专门为了解决委托安全问题诞生的是带访问限制的特殊委托。2. 事件与委托的核心区别权限限制事件只能在类内部触发外部只能订阅、取消订阅-不能直接赋值、不能主动触发安全性高杜绝外部覆盖逻辑、非法调用适合模块间通知语义不同委托是数据类型、用于传参调用事件是消息通知、用于触发回调3. 事件完整实战模拟任务完成通知场景后台任务执行完成自动触发事件通知所有订阅者执行回调逻辑。usingSystem;namespaceEventDemo{// 1. 定义委托规范事件签名publicdelegatevoidTaskFinishDelegate(stringtaskName);classTaskManager{// 2. 定义事件基于委托publiceventTaskFinishDelegateTaskFinishEvent;// 执行任务publicvoidRunTask(stringtaskName){Console.WriteLine($正在执行任务{taskName});// 任务执行完成触发事件通知所有订阅者TaskFinishEvent?.Invoke(taskName);}}classProgram{staticvoidMain(string[]args){TaskManagertaskManagernewTaskManager();// 订阅事件taskManager.TaskFinishEventLogFinish;taskManager.TaskFinishEventShowTip;// 执行任务自动触发所有订阅方法taskManager.RunTask(数据同步任务);}// 订阅方法1记录日志publicstaticvoidLogFinish(stringtaskName){Console.WriteLine($日志记录{taskName}执行完成);}// 订阅方法2弹窗提示publicstaticvoidShowTip(stringtaskName){Console.WriteLine($系统提示{taskName}已结束);}}}运行效果任务执行完成后自动依次执行日志记录、弹窗提示逻辑完全解耦六、委托事件核心实战模拟按钮点击事件我们日常Winform、WPF的按钮点击Button.Click本质就是事件机制手写模拟底层原理usingSystem;// 定义点击委托publicdelegatevoidClickDelegate();// 模拟按钮类publicclassButton{// 定义点击事件publiceventClickDelegateClick;// 模拟按钮被点击publicvoidOnClick(){Console.WriteLine(按钮被点击);// 触发事件Click?.Invoke();}}classProgram{staticvoidMain(){ButtonbtnnewButton();// 订阅点击事件btn.ClickBtn_Click;// 模拟用户点击按钮btn.OnClick();}// 点击回调逻辑privatestaticvoidBtn_Click(){Console.WriteLine(执行按钮点击业务逻辑提交表单);}}这就是所有界面事件的底层原理彻底看懂UI事件触发机制七、委托与事件核心区别总结面试必背定义方式委托用delegate事件用event委托访问权限委托公开可任意赋值、调用事件外部仅可订阅/取消安全可控使用场景委托用于方法传递、动态调用、参数封装事件用于消息通知、回调触发、模块解耦安全性委托不安全可被覆盖事件安全杜绝非法篡改八、新手高频易错坑点必避签名不匹配委托和绑定方法的返回值、参数必须完全一致否则报错空委托调用报错调用前必须判断非空推荐委托?.Invoke()极简判空写法混淆委托和事件需要动态调用用委托需要消息通知用事件滥用赋值符号多播绑定必须用 禁止直接 赋值会覆盖原有逻辑事件外部触发事件只能在定义类内部触发外部无法直接Invoke九、全文核心总结委托本质存储方法、传递方法的特殊类型实现动态调用、多播执行内置委托Action无返回值、Func有返回值覆盖99%开发场景精简写法匿名方法、Lambda表达式是委托的语法糖极简开发事件本质委托的安全升级版用于模块通知、回调触发、界面事件核心价值彻底解耦代码、实现回调机制是异步、多线程、UI编程的底层基石。下期预告下一篇我们将基于委托与事件精讲C# 异步编程与多线程彻底解决程序卡顿、耗时操作阻塞问题解锁高性能编程核心能力