C# 委托简述
1.委托
1.1什么是委托
委托委托 官网解释: 委托是安全封装方法的类型,类似于 C 和 C++ 中的函数指针。 与 C 函数指针不同的是,委托是面向对象的、类型安全的和可靠的。 委托的类型由委托的名称确定。
个人理解:委托就是一个方法的模板。它可以接收签名(签名一致就是方法的参数与返回值类型与其一致)与它一致的方法作为参数传递给它执行。
1.2 如何定义委托
使用关键字 delegate 声明委托
public delegate int GetNum(int a, int b);
除了使用delegate 定义 委托以外C#提供两个定义好的泛型委托 (Action 与 Func) (当然你也可以使用delegate自定义泛型委托)
这里先介绍两个C#定义的委托,相信很多人都在使用,不管你清不清楚什么是委托
Action:是无返回值的泛型委托。
下面action 表示无参,无返回值的委托
private void WTBtn_Click(object sender, EventArgs e)
{Action action = new Action(AA);//定义委托action();//使用方式1action.Invoke();//使用方式2
}private void AA()
{Console.WriteLine("我是传入的无参无返回值的委托方法");
}
下面action 表示有传入参数int,string无返回值的委托
private void WTBtn_Click(object sender, EventArgs e)
{Action<int,string> action = new Action<int, string>(AA);action(1,"");//使用方式1action.Invoke(1, "");//使用方式2
}private void AA(int a,string b)
{Console.WriteLine("我是传入的有参无返回值的委托方法");
}
Func:是有返回值的泛型委托。Func<object,string,int> object,string为参数。int为返回值
下面action 表示有传入参数int返回值string的委托
private void WTBtn_Click(object sender, EventArgs e)
{Func<int,string> action = new Func<int, string>(AA);//a=b="我是传入的有参无返回值的委托方法"var a = action(1);//使用方式1var b= action.Invoke(1);//使用方式2
}private string AA(int a)
{Console.WriteLine("我是传入的有参无返回值的委托方法");return "我是传入的有参无返回值的委托方法";
}
运行结果如下图:

下面action 表示有无参数有返回值string的委托
private void WTBtn_Click(object sender, EventArgs e)
{Func<string> action = new Func<string>(AA);//a=b="我是传入的有参无返回值的委托方法"var a = action();//使用方式1var b= action.Invoke();//使用方式2
}private string AA()
{Console.WriteLine("我是传入的有参无返回值的委托方法");return "我是传入的有参无返回值的委托方法";
}
C#自带的委托说完了,下面说 delegate 自定义的委托
下面代码定义了一个委托和一个静态类的方法。委托的级别与类等同,所以可以定义在命名空间里,当然也能定义在类里。
/// <summary>/// 定义委托/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public delegate int GetNum(int a, int b);public static class WTModel{/// <summary>/// 加法/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public static int Add(int a,int b){Console.WriteLine("执行Add了方法");return a + b;}/// <summary>/// 减法/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public static int Sub(int a, int b){Console.WriteLine("执行Sub了方法");return a - b;}/// <summary>/// 乘法/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public static int Multi(int a, int b){Console.WriteLine("执行Multi了方法");return a * b;}/// <summary>/// 除法/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public static int Division(int a, int b){Console.WriteLine("执行Division了方法");if (b == 0){return 0;}return a / b;}}
定义的GetNum委托与C#自带的两个委托是同级的,使用方式也是一页,只不C#自带的是泛型的,GetNum却是固定了两个参数为int类型且返回值是int类型的签名。故此能传入GetNum的方法的参数与返回值必须与GetNum保持一致。
使用方式:下面将上面Add方法传入委托并执行。
private void WTBtn_Click(object sender, EventArgs e)
{//实例化方式1GetNum num = new GetNum(WTModel.Add);//使用方法1var a = num(1, 2);//使用方法2var b = num.Invoke(1, 2);
}
执行结果:

值得注意的是,上述的委托执行方式都是同步的,并不是说把方法给到委托就会自动开启新的线程。看下面执行例子:
private void WTBtn_Click(object sender, EventArgs e)
{//实例化方式1GetNum num = new GetNum(WTModel.Add);//使用方法1var a = num(1, 2);//使用方法2var b = num.Invoke(1, 2);Console.WriteLine("我是一定是最后执行的");}
执行结果可初步看出是在委托执行了两次Add方法调用后才打印最后一段文字的(当然此处并不严谨,用于说明同步足够了):

那么如何异步执行呢 ,这里就不得不提BeginInvoke了 ,如下:
private void WTBtn_Click(object sender, EventArgs e){//实例化方式1GetNum num = new GetNum(WTModel.Add);//使用方法1var a = num(1, 2);//使用方法2//倒数第二个参数为回调函数,暂用null,//最后一个参数是给回调函数传入参数的参数,暂用null//IAsyncResult result = num.BeginInvoke(1, 2, null, null);var b = num.BeginInvoke(1,2,null,null);Console.WriteLine("我是不一定是最后执行的了");}
运行结果你看第二次调用Add就不一样了吧:

BeginInvoke在NetCore不支持,NetFamework支持 NetCore有更好的多线程功能来支持实现类似功能。所以在NET Core中需要自己手动去开启线程和实现异步。例如下面(在Famework里也可以这样使用异步):
/// <summary>/// 定义委托/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public delegate Task<int> GetNum(int a, int b);public static class WTModel{/// <summary>/// 加法/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public static Task<int> Add(int a, int b){return Task.Run(() =>{Console.WriteLine("执行Add了方法");return a + b;});}
}
private void WTBtn_Click(object sender, EventArgs e){//实例化方式1GetNum num = new GetNum(WTModel.Add);//使用方法1var a = num(1, 2);//使用方法2var b = num.Invoke(1,2);Console.WriteLine("我是不一定是最后执行的了");}
执行结果:

1.3:多播委托
所谓多播委托就是给委托传了多个方法,执行委托的时候会按照传入的顺序依次执行方法,当然传入的方法要注意错误处理,否则中件某个方法异常会导致后续方法无法执行,若委托有返回值,返回的值是最后一个方法的返回值。
定义多播(+=或者-=):
private void WTBtn_Click(object sender, EventArgs e){//多播委托//实例化方式1GetNum num = new GetNum(WTModel.Add);GetNum num1 = WTModel.Multi;//实例化方式2num += num1;num += WTModel.Sub;var c = num(1, 2);//调用一次会依次执行Add、Multi、Sub方法最终返回的值是最后一个委托的方法的返回值。}

1.4 实际应用
说了这么多,委托到底好在哪里呢,很多人都有这个疑问吧。下面举个例子就知道了 。
仍以上面定义的GetNum委托和其四个方法为基础。
正常我们要算加法直接使用Add方法不久一步到位了吗,为何还需要多此一举定义个委托来完成调用呢,这应该是很多看到这里的人的疑惑。
场景一:委托作为参数执行不同的方法,这样在WTBtn_Click方法中就只用调用Use1就能计算不同的值:
private void WTBtn_Click(object sender, EventArgs e)
{Use1(1, 2, WTModel.Add);Use1(1, 2, WTModel.Sub);Use1(1, 2, WTModel.Multi);Use1(1, 2, WTModel.Division);
}private void Use1(int a, int b, GetNum num)
{var A = num(1, 2);
}

场景2:实现根据不同地方输出产出的水果是啥
方法1:if或者switch以switch为例:
private string Use(string name)
{string a = "";switch (name){case "广州": a = "苹果"; break;case "重庆": a = "香蕉"; break;case "四川": a = "梨"; break;case "广西": a = "西瓜"; break;default: break;}return a;
}
使用:
Console.WriteLine(Use("广州"));
方法2:定义四个方法,分别调用方法
public static class WTModel
{public static void GZ(string name){if (name == "广州"){Console.WriteLine("苹果");}}public static void CQ(string name){if (name == "重庆"){Console.WriteLine("香蕉");}}public static void SC(string name){if (name == "四川"){Console.WriteLine("梨");}}public static void GX(string name){if (name == "广西"){Console.WriteLine("西瓜");}}
}
使用:
private void WTBtn_Click(object sender, EventArgs e)
{string name = "广州";WTModel.GZ(name);WTModel.GX(name);WTModel.CQ(name);WTModel.SC(name);}
方法3、使用委托:
定义委托和其四个方法
/// <summary>/// 定义委托/// </summary>/// <param name="a"></param>/// <param name="b"></param>/// <returns></returns>public delegate void GetName(string name);public static class WTModel{public static void GZ(string name){if (name == "广州"){Console.WriteLine("苹果");}}public static void CQ(string name){if (name == "重庆"){Console.WriteLine("香蕉");}}public static void SC(string name){if (name == "四川"){Console.WriteLine("梨");}}public static void GX(string name){if (name == "广西"){Console.WriteLine("西瓜");}}}
使用委托:
private void WTBtn_Click(object sender, EventArgs e)
{GetName get = WTModel.GZ;get += WTModel.GX;get += WTModel.CQ;get += WTModel.SC;Use("广州", get);
}private void Use(string name, GetName get)
{get.Invoke(name);
}
三个方法都可以实现根据地方不同输出相应水果。调用结果都是如下;

从三个方法写法和调用来看似乎方法一最为简单。
那么,现在你的程序已经是开发好了,这个时候突然来了两个需求。
需求1:新增一个地方的水果:
方法一需要新增一行case代码 。
方法二需要新增一个方法。
方法三需要新增一个方法。
看起来仍是方法一简单,但是 如果你使用的是是打包好的DLL文件,那么你就没办法直接增加代码,除非能重写方法。
需求2:在输出水果前先输出产地。
方法一 需要编辑每行case代码 。
方法二 需要编辑每个方法。
方法三 仅需在Use方法里新增一行即可。
若你使用的是是打包好的DLL文件且方法无法被重写,那似乎仅方法三能满足需求。
1.5 事件
本来准备单独说的,但事件本质是基于委托实现的观察者模式的应用。贴两个觉得可以的链接自行去看吧。
事件的理论即使用注意:C# 事件(event)_c# event-CSDN博客
事件的应用理解:分分钟用上C#中的委托和事件 - 雾中人 - 博客园
结语:个人认为委托的主要作用在于实现代码的重用,业务的解耦,保持代码的稳定性以及扩展性。暂时就说这么多吧,仅个人理解。
相关文章:
C# 委托简述
1.委托 1.1什么是委托 委托委托 官网解释: 委托是安全封装方法的类型,类似于 C 和 C 中的函数指针。 与 C 函数指针不同的是,委托是面向对象的、类型安全的和可靠的。 委托的类型由委托的名称确定。 个人理解:委托就是一个方法的模板。它可以接收…...
瑞吉外卖项目
目录 Day01业务开发 一、项目总体介绍与展示 二、软件开发整体介绍 (一)软件开发流程 三、瑞吉外卖项目介绍 (一)项目介绍 (二)技术选型功能架构 1.技术选型—— 编辑2.功能架构—— 编辑 &a…...
Docker:4、龙晰(Anolis OS 8.8)宝塔面板安装
接上文Docker:1、基于龙晰 (Anolis OS 8.8 )的基础镜像制作,本节我们介绍:基于Docker的龙晰(Anolis OS 8.8 )宝塔安装。 在第一节中由于我们对 Docker 容器进行了SSH设置,这为我们这…...
多端项目开发全流程详解 - 从需求分析到多端部署
引言 在当今互联网时代,一个完整的产品常常需要覆盖多个终端,包括小程序、Web端(后台管理系统)、App端等。本文将详细介绍一个采用前后端分离架构的多端项目开发流程,重点分析各个终端的特点、功能定位及其开发要点。…...
4.5KB原生html+js+css实现图片打印位置的坐标和尺寸获取
一般用于图片打印文字或图片的坐标获取,代码来自AI有改动。 功能:本地图选择后不上传直接可比划线条作为对角线得到矩形,动态显示坐标 按下鼠标开始松开鼠标结束。有细微BUG但不影响坐标获取。 <!DOCTYPE html> <html lang"en">…...
智诊小助手-记录模式选择
记录模式总共有连续记录、硬件触发、软件触发、错误触发四种模式选择,并且在选择完记录模式后还可以设置保留触发点前报文条数、存储时间、录制通道、保存类型 配置过程如下: 点击下面右图中模式选择即可进入到左图中的参数配置界面 如上图选择的配置…...
JDBC: Java数据库连接的桥梁
什么是JDBC? Java数据库连接(Java Database Connectivity,简称JDBC)是Java提供的一种API,允许Java应用程序与各种数据库进行交互。JDBC提供了一组标准的接口,开发者可以利用这些接口执行SQL语句、处理结果集…...
英伟达GPU算力【自用】
GPU(图形处理单元)算力的提升是驱动当代科技革命的核心力量之一,尤其在人工智能、深度学习、科学计算和超级计算机领域展现出了前所未有的影响力。2024年的GPU技术发展,不仅体现在游戏和图形处理的传统优势上,更在跨行…...
「C/C++」C++11 之 智能指针
✨博客主页何曾参静谧的博客📌文章专栏「C/C」C/C程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...
算法面试小抄
第一章:算法与数据结构要点速学 1.时间复杂度 (大 O) 首先,我们来谈谈常用操作的时间复杂度,按数据结构/算法划分。然后,我们将讨论给定输入大小的合理复杂性。 数组(动态数组/列表) 规定 n arr.length, 注意: &am…...
当有违法数据时,浏览器不解析,返回了undefined,导致数据不解析
现象:页面上没有看到数据 排查:断点到线上的源码里:1、协议回调确实没有拿到数据是个undefined 2、network里看服务确实响应了数据 3、控制台没有任何报错。 心情:莫名其妙的现象 我本地有json格式化工具,copy进去后&…...
在MySQL中ORDER BY使用的那种排序算法
在 MySQL 中,ORDER BY 子句的排序算法通常根据场景、数据量和表的索引情况而有所不同。MySQL 常用的排序算法包括: 文件排序(File Sort):MySQL 没有使用索引排序的情况下,会进行文件排序,这可以…...
学习threejs,使用粒子实现雨滴特效
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.Points简介1.11 ☘️…...
分布式-单元化架构1
一 两地三中心 1.1 两地三中心* 两地指的是两个城市:同城,异地。三中心指的是三个数据中心:生产中心、同城容灾中心、异地容灾中心。 在同一个城市或者临近的城市建设两个相同的系统,双中心具备相当的业务处理能力,…...
C++模板、STL
目录 一、模板 1、函数模板 (1)、基本语法和使用 (2)、函数模板注意事项 (3)、普通函数与函数模板的区别 (4)、普通函数与函数模板的调用规则 (5)、模板的局限性 2、类模板 (1)、基本语法 (2)、类模板与函数模板区别 (3)、类模板中成员函数创建时机 (4)、类模板对象…...
计算机视觉中的点算子:从零开始构建
Hey小伙伴们!今天我们要聊的是一个非常基础但极其重要的计算机视觉技术——点算子(Point Operators)。点算子主要用于对图像的每个像素进行独立的处理,比如亮度调整、对比度增强、灰度化等。通过这些简单的操作,我们可…...
国际中文教育知识图谱问答
你还在为毕业设计头疼么?想快速搭建一个智能化系统,展示数据又能精准回答问题?那你绝对不能错过这个超实用的 知识图谱问答系统,特别适用于需要整合复杂数据关系、交互性强的项目! 这个系统基于 Neo4j图数据库 开发&a…...
酒店大板轻触开关与传统的开关有什么区别
酒店大板轻触开关与传统的开关在功能、设计、使用方式以及安装维护等多个方面都存在显著的差异。以下是对这些差异的详细分析: 功能差异 酒店大板轻触开关: 多功能性:酒店大板轻触开关通常集成了多种功能,如控制照明、窗帘、夜灯、…...
【蓝桥杯选拔赛真题78】python电话号码 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析
目录 python电话号码 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python电话号码 第十五届蓝桥杯青少年组python比赛选拔赛真题 一、题目要…...
对比两个json串的diff,支持map的深度递归
背景 项目重构,对老接口进行技术改造。动代码后,难免会有些bug,我们需要对比改造前后接口的返回,来判断逻辑是否有问题,这就涉及两个json的对比。 常规的diff文本工具是按行对比,无法处理复杂的map。本文通…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
