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#中的委托和事件 - 雾中人 - 博客园

结语:个人认为委托的主要作用在于实现代码的重用,业务的解耦,保持代码的稳定性以及扩展性。暂时就说这么多吧,仅个人理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/456191.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ASP.NET MVC-font awesome-localhost可用IIS不可用

环境&#xff1a; win10, .NET 6.0&#xff0c;IIS 问题描述 本地IIS正常显示&#xff0c;但放到远程服务器上&#xff0c;每个icon都显示?。同时浏览器的控制台报错&#xff1a; fontawesome-webfont.woff2:1 Failed to load resource: the server responded with a statu…

uni-app 开发微信小程序,实现图片预览和保存

1.使用 uni.previewImage() 预览图片 1.1 图片列表 1.2 预览 1.2.1 样式无法调整 1.2.2 微信小程序不支持预览本地文件路径图片&#xff08;图片上传到小程序的临时文件存储或云服务存储&#xff09; 1.3 无法绑定 longpress"saveImage(item)" 长按保存图片事件 …

NewStarCTF 2023 公开赛道 Web week1-week2

目录 week1 泄漏的秘密 Begin of Upload Begin of HTTP ErrorFlask ​Begin of PHP R!C!E! EasyLogin ​week2 游戏高手 include 0。0 ez_sql ​Unserialize&#xff1f; Upload again! R!!C!!E!! week1 泄漏的秘密 使用ctf-scan.py&#xff08;https://gith…

写在RAGFlow开源2万星标之际

RAGFlow自2024年4月1日正式开源&#xff0c;时至今日&#xff0c;不到7个月时间已经站在了Github 2万星标的台阶之上。在6月底Github 1万星标的时候&#xff0c;我们曾经写了一篇文章&#xff0c;提出RAG 2.0的口号【参考文献1】&#xff0c;论述了RAG作为一种以搜索为中心的系…

排查PHP服务器CPU占用率高的问题

排查PHP服务器CPU占用率高的问题通常可以通过以下步骤进行&#xff1a; 使用top或htop命令&#xff1a;这些命令可以实时显示服务器上各个进程的CPU和内存使用情况。找到CPU使用率高的进程。 查看进程日志&#xff1a;如果PHP-FPM或Apache等服务器进程的日志记录了具体的请求…

2005至2023年中国各地区数据要素化水平-最新出炉 附下载链接

中国各地区数据要素化水平&#xff08;2005-2023年&#xff09;概览 下载链接-点它&#x1f449;&#x1f449;&#x1f449;&#xff1a;2005至2023年中国各地区数据要素化水平-最新出炉.zip 一、数据背景与意义 在数字经济和数字技术持续发展的浪潮中&#xff0c;数据已逐…

php命令执行的一些执行函数----以ctfshow靶场为解题思路

解法10、利用文件包含 ①?cinclude$_GET[1]?>&1data://text/plain,<?php system(tac flag.php);?> cdata://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg ②?cinclude$_GET[1]?>&1php://filter/readconvert.base64-encode/resourc…

在Java中,需要每120分钟刷新一次的`assetoken`,并且你想使用Redis作为缓存来存储和管理这个令牌

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

k8s部署使用有状态服务statefulset部署eureka集群,需登录认证

一、构建eureka集群镜像 1、编写dockerfile文件&#xff0c;此处基础镜像为arm版本&#xff0c;eureka目录中文件内容&#xff1a;application-dev.yml、Dockerfile、eureka-server-1.0-SNAPSHOT.jar(添加登录认证模块&#xff0c;文章最后附上下载连接) FROM mdsol/java8-j…

Vue入门示例

今天滴学习目标&#xff01;&#xff01;&#xff01; 示例简介HTML内容主体区域输入框列表区域统计和清空 JS引入Vue.js库定义Vue实例el选项data选项methods选项 示例简介 HTML内容 本次实例讲解的是v-for、v-on、v-model来写这小小的实例&#xff0c;下面是实例的效果图&am…

OQE-OPTICAL AND QUANTUM ELECTRONICS

文章目录 一、征稿简介二、重要信息三、服务简述四、投稿须知五、联系咨询 一、征稿简介 二、重要信息 期刊官网&#xff1a;https://ais.cn/u/3eEJNv 三、服务简述 四、投稿须知 1.在线投稿&#xff1a;由艾思科蓝支持在线投稿&#xff0c;请将文章全文投稿至艾思科蓝投稿系…

国家能源集团携手海康威视研发攻克融合光谱煤质快检技术

10月24日&#xff0c;在国家能源集团准能集团黑岱沟露天煤矿&#xff0c;安装于准能选煤厂785商品煤胶带机中部的煤质快检核心设备&#xff0c;正在对当天装车外运的商品煤煤质进行实时检测。仅两分钟后&#xff0c;涵盖发热量、水分、灰分、硫分等多项指标的数据信息已传输到到…

在xml 中 不等式 做转义处理的问题

对于这种要做转义处理&#xff0c;<![CDATA[ < ]]>

LeetCode_509. 斐波那契数_java

1、题目 509. 斐波那契数https://leetcode.cn/problems/fibonacci-number/ 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#…

Discuz 论坛开发一套传奇发布站与传奇开服表

Discuz 论坛开发一套传奇发布站与传奇开服表 随着互联网技术的飞速发展&#xff0c;网络游戏已成为人们休闲娱乐的重要方式之一。在众多网络游戏中&#xff0c;传奇系列以其独特的魅力吸引了大量忠实玩家。为了满足这些玩家的需求&#xff0c;并促进游戏信息的交流与分享&…

密码学原理

1.1 加密算法 Tags: 1、加密算法分类 2、对称算法 <原理、特征、算法> 3、非对称算法 <原理、特征、算法> 4、对称算法vs非对称算法 <结合体> 1、加密算法概述&#xff1a; 用于对用户数据进行加密&#xff0c;常用算法有DES、3DES、AES、RSA、DH算法。根据密…

合约门合同全生命周期管理系统:企业合同管理的数字化转型之道

合约门合同全生命周期管理系统&#xff1a;企业合同管理的数字化转型之道 1. 引言 在现代企业中&#xff0c;合同管理已经不再是简单的文件存储和审批流程&#xff0c;而是企业合规性、风险管理和业务流程的关键环节之一。随着企业规模的扩大和合同数量的增加&#xff0c;传统…

Linux下MySQL8.x的编译安装与使用

Linux下MySQL的安装与配置 1. 安装环境初始化 1.1 查看是否安装过MySQL 如果使用rpm安装, 检查一下RPM PACKAGE rpm -qa | grep -i mysql # -i 忽略大小写 # 或者 yum list installed | grep mysql如果存在mysql-libs的旧版本包&#xff0c;显示如下 #存在 [rootlocalhost ~]…

NavMesh只制作可移动的导航网,清除多余不可走区域

只制作可移动的导航网。它使存储文件大小减小并提高性能。它消除了迁移到随机区域的问题。添加链接描述 1.如何使用 2.创建一个包含“NavMeshCleaner”组件的对象。Andadd指向可定制区域。 按住控制键并单击添加点。如果要移动它&#xff0c;请按 输入上的control键并单击。您…

信息安全工程师(55)网络安全漏洞概述

一、定义 网络安全漏洞&#xff0c;又称为脆弱性&#xff0c;是网络安全信息系统中与安全策略相冲突的缺陷&#xff0c;这种缺陷也称为安全隐患。漏洞可能导致机密性受损、完整性破坏、可用性降低、抗抵赖性缺失、可控性下降、真实性不保等问题。 二、分类 网络安全漏洞可以根据…