当前位置: 首页 > news >正文

C# 委托简述

1.委托

    1.1什么是委托

委托委托        官网解释: 委托是安全封装方法的类型,类似于 C 和 C++ 中的函数指针。 与 C 函数指针不同的是,委托是面向对象的、类型安全的和可靠的。 委托的类型由委托的名称确定。

        个人理解:委托就是一个方法的模板。它可以接收签名(签名一致就是方法的参数与返回值类型与其一致)与它一致的方法作为参数传递给它执行。

     1.2 如何定义委托

                使用关键字 delegate 声明委托

public delegate int GetNum(int a, int b);

                除了使用delegate 定义 委托以外C#提供两个定义好的泛型委托 (ActionFunc) (当然你也可以使用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,intobject,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什么是委托 委托委托 官网解释: 委托是安全封装方法的类型&#xff0c;类似于 C 和 C 中的函数指针。 与 C 函数指针不同的是&#xff0c;委托是面向对象的、类型安全的和可靠的。 委托的类型由委托的名称确定。 个人理解:委托就是一个方法的模板。它可以接收…...

瑞吉外卖项目

目录 Day01业务开发 一、项目总体介绍与展示 二、软件开发整体介绍 &#xff08;一&#xff09;软件开发流程 三、瑞吉外卖项目介绍 &#xff08;一&#xff09;项目介绍 &#xff08;二&#xff09;技术选型功能架构 1.技术选型—— ​编辑2.功能架构—— ​编辑 &a…...

Docker:4、龙晰(Anolis OS 8.8)宝塔面板安装

接上文Docker&#xff1a;1、基于龙晰 &#xff08;Anolis OS 8.8 &#xff09;的基础镜像制作&#xff0c;本节我们介绍&#xff1a;基于Docker的龙晰&#xff08;Anolis OS 8.8 &#xff09;宝塔安装。 在第一节中由于我们对 Docker 容器进行了SSH设置&#xff0c;这为我们这…...

多端项目开发全流程详解 - 从需求分析到多端部署

引言 在当今互联网时代&#xff0c;一个完整的产品常常需要覆盖多个终端&#xff0c;包括小程序、Web端&#xff08;后台管理系统&#xff09;、App端等。本文将详细介绍一个采用前后端分离架构的多端项目开发流程&#xff0c;重点分析各个终端的特点、功能定位及其开发要点。…...

4.5KB原生html+js+css实现图片打印位置的坐标和尺寸获取

一般用于图片打印文字或图片的坐标获取,代码来自AI有改动。 功能&#xff1a;本地图选择后不上传直接可比划线条作为对角线得到矩形&#xff0c;动态显示坐标 按下鼠标开始松开鼠标结束。有细微BUG但不影响坐标获取。 <!DOCTYPE html> <html lang"en">…...

智诊小助手-记录模式选择

记录模式总共有连续记录、硬件触发、软件触发、错误触发四种模式选择&#xff0c;并且在选择完记录模式后还可以设置保留触发点前报文条数、存储时间、录制通道、保存类型 配置过程如下&#xff1a; 点击下面右图中模式选择即可进入到左图中的参数配置界面 如上图选择的配置…...

JDBC: Java数据库连接的桥梁

什么是JDBC&#xff1f; Java数据库连接&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java提供的一种API&#xff0c;允许Java应用程序与各种数据库进行交互。JDBC提供了一组标准的接口&#xff0c;开发者可以利用这些接口执行SQL语句、处理结果集…...

英伟达GPU算力【自用】

GPU&#xff08;图形处理单元&#xff09;算力的提升是驱动当代科技革命的核心力量之一&#xff0c;尤其在人工智能、深度学习、科学计算和超级计算机领域展现出了前所未有的影响力。2024年的GPU技术发展&#xff0c;不仅体现在游戏和图形处理的传统优势上&#xff0c;更在跨行…...

「C/C++」C++11 之 智能指针

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…...

算法面试小抄

第一章:算法与数据结构要点速学 1.时间复杂度 (大 O) 首先&#xff0c;我们来谈谈常用操作的时间复杂度&#xff0c;按数据结构/算法划分。然后&#xff0c;我们将讨论给定输入大小的合理复杂性。 数组&#xff08;动态数组/列表&#xff09; 规定 n arr.length, 注意: &am…...

当有违法数据时,浏览器不解析,返回了undefined,导致数据不解析

现象&#xff1a;页面上没有看到数据 排查&#xff1a;断点到线上的源码里&#xff1a;1、协议回调确实没有拿到数据是个undefined 2、network里看服务确实响应了数据 3、控制台没有任何报错。 心情&#xff1a;莫名其妙的现象 我本地有json格式化工具&#xff0c;copy进去后&…...

在MySQL中ORDER BY使用的那种排序算法

在 MySQL 中&#xff0c;ORDER BY 子句的排序算法通常根据场景、数据量和表的索引情况而有所不同。MySQL 常用的排序算法包括&#xff1a; 文件排序&#xff08;File Sort&#xff09;&#xff1a;MySQL 没有使用索引排序的情况下&#xff0c;会进行文件排序&#xff0c;这可以…...

学习threejs,使用粒子实现雨滴特效

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Points简介1.11 ☘️…...

分布式-单元化架构1

一 两地三中心 1.1 两地三中心* 两地指的是两个城市&#xff1a;同城&#xff0c;异地。三中心指的是三个数据中心&#xff1a;生产中心、同城容灾中心、异地容灾中心。 在同一个城市或者临近的城市建设两个相同的系统&#xff0c;双中心具备相当的业务处理能力&#xff0c;…...

C++模板、STL

目录 一、模板 1、函数模板 (1)、基本语法和使用 (2)、函数模板注意事项 (3)、普通函数与函数模板的区别 (4)、普通函数与函数模板的调用规则 (5)、模板的局限性 2、类模板 (1)、基本语法 (2)、类模板与函数模板区别 (3)、类模板中成员函数创建时机 (4)、类模板对象…...

计算机视觉中的点算子:从零开始构建

Hey小伙伴们&#xff01;今天我们要聊的是一个非常基础但极其重要的计算机视觉技术——点算子&#xff08;Point Operators&#xff09;。点算子主要用于对图像的每个像素进行独立的处理&#xff0c;比如亮度调整、对比度增强、灰度化等。通过这些简单的操作&#xff0c;我们可…...

国际中文教育知识图谱问答

你还在为毕业设计头疼么&#xff1f;想快速搭建一个智能化系统&#xff0c;展示数据又能精准回答问题&#xff1f;那你绝对不能错过这个超实用的 知识图谱问答系统&#xff0c;特别适用于需要整合复杂数据关系、交互性强的项目&#xff01; 这个系统基于 Neo4j图数据库 开发&a…...

酒店大板轻触开关与传统的开关有什么区别

酒店大板轻触开关与传统的开关在功能、设计、使用方式以及安装维护等多个方面都存在显著的差异。以下是对这些差异的详细分析&#xff1a; 功能差异 酒店大板轻触开关&#xff1a; 多功能性&#xff1a;酒店大板轻触开关通常集成了多种功能&#xff0c;如控制照明、窗帘、夜灯、…...

【蓝桥杯选拔赛真题78】python电话号码 第十五届青少年组蓝桥杯python选拔赛真题 算法思维真题解析

目录 python电话号码 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python电话号码 第十五届蓝桥杯青少年组python比赛选拔赛真题 一、题目要…...

对比两个json串的diff,支持map的深度递归

背景 项目重构&#xff0c;对老接口进行技术改造。动代码后&#xff0c;难免会有些bug&#xff0c;我们需要对比改造前后接口的返回&#xff0c;来判断逻辑是否有问题&#xff0c;这就涉及两个json的对比。 常规的diff文本工具是按行对比&#xff0c;无法处理复杂的map。本文通…...

【我的创作纪念日1024】

我的创作纪念日1024 机缘成就明年的规划 机缘 过去的1024个日子里&#xff0c;我在专业发展、职场和发展、科技创新创业、软件开发、人工智能、虚拟现实、区块链等栏目分享了一些工作和学习的建议和体会。尤其是在2022年&#xff0c;我连续发布100篇的博文&#xff0c;不仅仅是…...

萤石设备视频接入平台EasyCVR私有化视频平台变电站如何实现远程集中监控?

一、方案背景 随着城市经济的发展和电力系统的改造&#xff0c;变电站的数量和规模逐渐增加&#xff0c;对变电站的安全管理和监控需求也越来越高。视频监控系统作为重要的安全管理手段&#xff0c;在变电站中起到了关键的作用。 目前青犀视频研发的萤石设备视频接入平台EasyC…...

什么是多线程?请描述 Java 中实现多线程的基本方式?

今天和大家探讨一下 Java 中的多线程&#xff0c;包括它的基本概念、实现方式以及一些实际开发中的注意事项。 什么是多线程&#xff1f; 多线程是指在一个程序中存在多个执行流&#xff0c;每个执行流都可以独立于其他执行流执行。 在 Java 中&#xff0c;多线程允许开发者…...

Dynamic Sparse No Training: Training-Free Fine-tuning for Sparse LLMs

大语言模型&#xff08;LLM&#xff09;在设备上部署道路上落下了一个令人生畏的障碍。本文关注于大语言模型的剪枝算法。 动态稀疏训练&#xff08;Dynamic Sparse Training&#xff0c;DST&#xff09;是一种近期收到广泛关注的剪枝算法。与之前大部分剪枝方法需要训练整个网…...

解决n+1查询数据库问题

文章目录 1. 问题描述2. 解决方法3. 总结 1. 问题描述 在写项目中&#xff0c;可能会碰到一个问题&#xff1a;通过查询表A得到一个list结果&#xff0c;再对list中的n个元素各查询一次关联的表B。形成对数据库执行n1次查询。这种代码会无形增加数据库的处理负担&#xff0c;影…...

DICOM 基础知识:深入理解DICOM数据结构与标签说明

目录 DICOM 图像概念 DICOM 图像关键特性&#xff1a; DICOM 文件结构 常见数据元素&#xff1a; 数据元素示例详解 DICOM-VR 数据类型说明 DICOM 标准支持的数据集 结语 DICOM 图像概念 DICOM&#xff08;Digital Imaging and Communications in Medicine&…...

Git - 如何删除 push 过一次的文件链路追踪?

&#xff08;以 target 文件夹为例&#xff09;如果你已经在 .gitignore 中添加了 target/ 目录&#xff0c;但 target 文件夹仍然出现在 Git 的变更列表中&#xff0c;可能是因为它之前已经被添加到 Git 仓库中。即使你更新了 .gitignore&#xff0c;Git 仍然会跟踪这些文件。…...

软件测试学习总结

一.软件测试概念和目的 软件测试的概念: 测试模型(V模型) 软件测试就是在软件投入运行前,对软件需求分析、设计规格说明和编码实现的最终审查,它是软件质量保证的关键步骤。 通常对软件测试的定义有两种描述: 定义1:软件测试是为了发现错误而执行程序的过程 定义2:…...

c语言错题——#define对应的查找替换

文章目录 一、题目 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、题目 分析 结构体向最长的char对齐&#xff0c;前两个位段元素一共42位&#xff0c;不足8位&#xff0c;合起来占1字节&#xff0c;最后一个单独1字节&#xff0c;一共3字节。另外…...

Visual Basic介绍及简单例子

Visual Basic(简称 VB)是一种由微软公司开发的包含协助开发环境的事件驱动编程语言。 一、主要特点 易于学习和使用: Visual Basic 具有直观的可视化开发环境,使用户可以通过拖放控件和设置属性的方式快速创建用户界面。对于初学者来说,这种方式非常容易上手,无需深入了…...