C#中的委托是什么

news2024/9/22 3:29:26

https://www.cnblogs.com/deepalley/p/12150931.html

1.什么是委托?(方法作另一个方法的参数)
delegate void MyDel(int value);    //声明委托类型
和类一样,委托是用户自定义的类型,但是类是数据和方法的集合,而委托是持有一个或多个方法。
delegate可以看做是一个包含有序方法列表的对象,这些方法具有相同的签名和返回类型。
委托保存的方法可以来自任何类或结构
调用列表中的方法可以是实例方法也可以是静态方法
调用委托时,会执行调用列表中的所有方法


2.声明委托类型
delegate    void      MyDel        (int value);委托的是无返回值,且单一int参数的方法
关键字    返回类型    委托类签名      签名

3.创建委托对象
MyDel       delVar;
委托类型     变量
delVar = new MyDel(myInstObj.MyM1);    或    delVar = myInstObj.MyM1;
delVar = new MyDel(sClass.otherM2);    或    delVar = sClass.otherM2;

4.组合委托
MyDel a = myInstObj.myM1;
MyDel b = SClass.OtherM2;
MyDel c = a + b;

5.为委托添加方法+=  同理删除方法: -=
MyDel delVar = inst.myM1;    //创建并初始化
delVar += Scl.m3;
delVar += X.Act;

6.调用委托(从底部函数开始执行)
MyDel delVar = inst.MyM1;
delVar(55);

7.调用带返回值的委托
最后一个方法的返回值就是委托调用返回的值,其他方法的返回值会被忽略

8.调用带引用参数的委托
参数值会根据调用列表中的一个或多个方法的返回值而改变

9.匿名方法
在初始化委托时内联声明的方法
delegate   (Parameters)    {ImplementationCode}
关键字      参数列表        语句块
delegate int OtherDel(int Inparam);
static void Main()
{
    OtherDel del = delegate(int x)
    {
        return x + 20;
    };
}

为什么使用委托:在我们编写程序的时候,程序的上下文是固定的,在某个关键的部分,不确定调用哪个函数,这时候需要让程序更换被调用函数,又不想两个函数耦合性太高,使用委托可实现间接调用,或者可替换调用

 

什么时候该用委托,为什么要用委托,委托有什么好处

我用的最多的是在多线程 访问UI界面控件的时候。
UI控件都由主线程创建和绘制的,如果子线程想访问控件的话,就把这个任务委托给主线程。
比如有个子线程 想要给 form中的label控件赋值 Label.Text="内容"
此时必须用委托让主线程去执行这个赋值语句。
如果不这么做,会出现线程安全的异常。产生多个线程同时访问同一个控件的异常。这是不符合线程安全的要求的

 C#语法——委托,架构的血液

本篇文章主要介绍委托的应用。

委托是大家最常见的语法了,但会用与精通之间的差别是巨大的。

一个程序员如果不能精通委托,那么,他永远无法成为高级程序员。

所以,让我们把委托刻到血液里吧。

这样,你才能称为[Developer]。

委托的定义

什么是委托?

委托实际上是一种类型,是一种引用类型。

微软用delegate关键字来声明委托,delegate与int,string,double等关键字一样。都是声明用的。

下面先看下声明代码,这里声明了两个委托。

1

2

public delegate void TestDelegate(string message);

public delegate int TestDelegate(MyType m, long num);

delegate既然是关键字,和int,string一样,那么,为什么delegate后又跟了一个void或者int呢?

如果他们是同等地位的关键字,为什么可以一起使用呢?

很简单,我们把delegate后面的 【void TestDelegate(string message)】理解为一个变量,是不是就清晰明了了一些。

我们把delegate关键字理解为,是用来专门来定义这种复杂的变量的。而这种复杂的变量可以包含一个返回值和任意数目任意类型的传入参数。

有没有感觉,这个复杂的变量特别像一个函数的定义。

没错,官方定义,委托类型的声明与方法签名相似。所以,这个复杂变量,的确,书写的方式就是与函数一样。

那么,为什么这个声明方式如此怪异呢,是因为,我们用delegate定义的变量,只能用函数赋值。赋值方式如下所示:

1

2

3

4

5

6

7

8

9

10

public delegate void TestDelegate(string message);

public delegate long TestDelegate2(int m, long num);

public static void Excute()

{

    TestDelegate2 td = Double;

}

static long Double(int m, long num)

{

    return m * num;

}

委托的基本应用

学会了赋值以后,我开始使用委托。

委托的使用方式如下:

1

2

string result = td(51, 8);

Console.WriteLine(result);

这里我们会发现,委托的使用方式与函数调用一样。

没错,它们的确是一样的。因为委托是用函数来赋值的,所以调用方式一样也并不奇怪,不是吗。

换一种说法,就是委托封装了一个函数。

如果委托是封装的函数,并且它又是引用类型。那么委托第一种常规的应用就浮现出来了。

那就是——引用类型的函数。

如果函数是引用类型,那么这个函数只要没被内存回收,就可以被调用。如果是public函数或者是public static函数,那么它能跨越的东西就更多了。

比如可以跨类调用,跨程序集调用等等。而这种用法,就是委托的基本应用。

匿名委托的应用

匿名委托的官方介绍:在 2.0 之前的 C# 版本中,声明委托的唯一方式是使用命名方法。 C# 2.0 引入匿名方法,在 C# 3.0 及更高版本中,Lambda 表达式取代匿名方法作为编写内联代码的首选方式。

看不懂没关系,我们直接来学习使用。代码如下:

1

2

3

4

5

6

delegate string anonymousDelegate(int m, long num);

public static void Excute()

{

    anonymousDelegate ad = delegate (int m, long num) { return m.ToString() + num.ToString(); };//2.0时代的匿名委托

    anonymousDelegate ad2 = (m, num) => { return m.ToString() + num.ToString(); };//3.0以后匿名委托

}

如代码所示,匿名委托是Lambda表达式,不懂的同学就当它是有固定写法即可,不用讲什么道理,只要记住并应用即可。

匿名委托虽然减少了一点代码,但还是要求我们自己去声明委托。所有,还能再简写一点吗?

答案当然是,可以的。

Action与Func

Action与Func是微软为我们预先定义好了的,两个委托变量。其中Action是不带返回值的委托,Func是带返回值的委托。

可以说,Action与Func完全包含了,我们日常使用所需的,全部的,委托变量。

也就是说,我们可以不用再去自己手动声明委托了。

下面来看最简单的Action与Func的定义:

1

2

Action a1 = () => { };

Func<int> f1 = () => { return 1; };//必须写 return 1;

Action与Func是泛型委托,各支持16个入参变量。下面代码为一个入参的定义,多参数以此类推。

1

2

Action<int> a1 = (i) =>  { };

Func<string,int> f1 = (str) => {  return 1;//必须写 return 1; };

委托的线程应用

委托的线程应用是委托的第二种用法,分为线程使用委托,和委托的异步应用两种。

我们先看线程使用委托。如下代码所示,一个无入参匿名Action和一个无入参匿名Func。

1

2

3

4

5

Task taskAction = new Task(() => { });//无入参匿名Action

taskAction.Start();

Task<int> taskFunc = new Task<int>(() => { return 1; });//无入参匿名Func

taskFunc.Start();

int result= taskFunc.GetAwaiter().GetResult();//获取线程返回结果

我们能看到两种委托应用,代码都非常简洁。

下面我们再来看委托的异步应用。首先看最简单的异步调用。

1

2

3

4

5

6

7

8

9

10

Action action = new Action(() => { });

IAsyncResult result = action.BeginInvoke((iar) =>

{

}, null);

Func<int> func = new Func<int>(() => { return 1; }); 

IAsyncResult resultfunc = func.BeginInvoke((iar) =>

{

    var res = func.EndInvoke(iar);

}, null);

这里我们使用委托的BeginInvoke方法来开启线程,进行异步调用。如上面代码所示,这里介绍了Action与Func的最基础的异步应用。

委托,架构的血液

委托是架构的血液,如果系统中没有委托,那代码将堆叠到一起,比大力胶粘的都紧密。

就好比一碗汤面倒掉了所有的汤,只要它静放一个阵子,就会变成一坨面球,让你无从下嘴。

所以,委托是架构的血液,是框架的流畅的基石。

那么委托到底是如何流动的呢?

我们先从刚介绍过的委托的线程应用说起。

----------------------------------------------------------------------------------------------------

第一核心应用——随手线程:

我们在做开发的时候,一定接触过父类。父类是干什么的呢?父类通常是用来编写公共属性和函数,方便子类调用的。

那我们的委托的第一个核心应用,就是父类的公共函数,线程随手启动。如何随手开启呢?

首先,我们创建父类代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

class BaseDelegateSyntax

{

    public void AsyncLoad(Action action)

    {

    }

    public void AsyncLoad(Action action, Action callback)

    {

        IAsyncResult result = action.BeginInvoke((iar) =>

        {

            callback();

        }, null);

    }

    public void AsyncLoad<T>(Action<T> action, T para, Action callback)

    {

        IAsyncResult result = action.BeginInvoke(para, (iar) =>

        {

            callback();

        }, null);

    }

    public void AsyncLoad<T, R>(Func<T, R> action, T para, Action<R> callback)

    {

        IAsyncResult result = action.BeginInvoke(para, (iar) =>

        {

            var res = action.EndInvoke(iar);

            callback(res);

        }, null);

    }

}

我们看到上面的代码,父类中添加了四个异步委托的调用函数,接下来,我们就可以在继承该类的子类中,随手开启线程了。

子类代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

class ChildDelegateSyntax : BaseDelegateSyntax

{

    public void Excute()

    {

        //开启异步方法

        base.AsyncLoad(() => { });

        //开启异步方法,并且在异步结束后,触发回调方法

        base.AsyncLoad(() => { },

            ()=>

            {

                //我是回调方法

            });

        //开启异步有入参的方法,传递参数,并且在异步结束后,触发回调方法

        base.AsyncLoad<string>((s) => { },"Kiba518",

           () =>

           {

                //我是回调方法

           });

        //开启异步有入参的方法,传递字符串参数Kiba518,之后返回int型结果518,

        //并且在异步结束后,触发回调方法,回调函数中可以获得结果518

        base.AsyncLoad<string,int>((s) => {

            return 518;

        }, "Kiba518",

           (result) =>

           {

               //我是回调方法 result是返回值518

           });

    }

}

看了上面的父子类后,是否感觉委托让我们繁杂的线程世界变简洁了呢?

----------------------------------------------------------------------------------------------------

第二核心应用——穿越你的世界:

接下来,我们来看委托的第二种核心用法,穿越的应用。

这个应用,是最常见,也最普通的应用了。因为委托是引用类型,所以A类里定义的委托,可以在被内存回收之前,被其他类调用。

我们经常会在各种论坛看到有人发问,A页面如何调用B页面的属性、方法、父页面获取子页面的属性、方法,或者子页面获取父页面的属性、方法。

其实,只要定义好委托,并将委托正确的传递,就可以实现穿越的调用了。

下面我们看下穿越应用的代码。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public class FirstDelegateSyntax

{

    public FirstDelegateSyntax()

    {

        Console.WriteLine(" First 开始 "  );

        SecondDelegateSyntax sds = new SecondDelegateSyntax(()=> {

            Console.WriteLine(" First传给Second委托被触发 ");

        });

        sds.Excute();

        Console.WriteLine(" First 结束 ");

    }

}

public class SecondDelegateSyntax

{

    public Action Action { getset; }

    public SecondDelegateSyntax(Action _action)

    {

        Console.WriteLine(" Second的构造函数 ");

        Action = _action;

    }

    public void Excute()

    {

        Console.WriteLine(" Second的Excute被触发 ");

        Action();

    }

}

我们可以看到,我们传递的委托,穿越了自身所属的类。在SecondDelegateSyntax类中被触发了。

运行结果如下:

第三核心应用——回调函数:

世界上本没有回调函数,叫的人多了,也就有了。

请记住,所有的回调函数,都是委托的穿越应用,所有的回调函数;都是委托的穿越应用;所有的回调函数,都是委托的穿越应用。

重要的话要讲三遍。

因为委托是引用类型,所以可以被[址传递]。函数是不可以被传递的。

当你传递函数的时候,其实是匿名传递了一个委托的地址。

结语

委托是我们最常用的语法,它将函数封装成引用类型的变量,供其他单位调用。

因为委托的特质是引用类型,所以决定了委托是可以进行址传递。也就是说,委托是穿梭于我们系统代码中的列车。

我们可以在列车上放很多很多东西,在需要的站点,叫停列车,并将托运的东西搬下来使用。

所以,理论上,只要我们利用好委托,就可以大量减少冗余的代码。

但委托这种列车,是每个程序员都可以定义的,如果一个项目中有十个开发者,每个人都在定义委托,那么,就有可能出现定义了十个相同的委托的情况,这样就出现了撞车的现象。

所以委托在使用的时候,尽量做到有序传递,即预先做好列车的行驶路线,让委托按照路径运行。尽量不要定义可以被任何单位调用的公共委托。

如果需要公共委托,可以采取反射的方式来调用。

模板方法(把委托当作参数传递到方法里去,通过传进的委托参数,它“借用”制定的外部方法,来产生一个结果)

模板方法的好处是什么呢?一旦我们把代码写成了这样只会,我们的GetTopNum方法呢,就不需要去动它了

 我们只需要的是不断扩张,我们之后想比较的成员变量就可以计算出,玩家每个成员中最高的玩家的名字(比如说我们之后增加了【金币数】GetTopNum方法就不用动,只要新增一个小方法,如果用Lambda表达式的话,小方法也可以省去)我们不用去管我们计算的到底是哪个数据,我们只要把方法封装在一个委托类型的变量中,作为参数来传递,传递到我们的模板方法中,我们的模板方法就一定可以计算出。某一个成员变量它的最高值

 

 这里呢,就是初步介绍,如何通过[lambda表达式]当作一个实际参数,传递给方法的参数中

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue实现功能完整的购物商城,商品零食、电商通用商城

目录 一、项目结构 1.项目截图 2.项目简介 3.项目布局 二、首页 1.效果图 2.源码 三、商品详情 1.效果图 2.源码 四、分类 1.效果图 五、购物车、提交订单 1.效果图 六、个人中心 1.源码结构 2、效果图 七、总结 一、项目结构 1.项目截图 2.项目简介 项目基于vue…

海睿思分享 | 一文读懂企业数据资产目录建设的重要性

小王是某公司信息化部门负责人。 某天&#xff0c;公司领导需要获取近三年来生产部门的人员信息全面数据&#xff0c;小王费了九牛二虎之力&#xff0c;召开了各种会议&#xff0c;在各个系统里来回找数据&#xff0c;最终找到了这些数据。然而领导所需的人员职称、人员获奖信…

UOS服务器系统配置bond

一、Bond介绍 bond可以将多个网卡绑定到一起&#xff0c;可以让两个或多个接口作为一个接口&#xff0c;同时提高带宽&#xff0c;并提供网络链路的冗余&#xff0c;当有其中一块网卡故障的时候&#xff0c;不会中断服务器的业务。 二、Bond模式 1、mode0&#xff08;balanc…

老杨说运维 | 运维数智化转型正确打开方式是什么?他这样说

2023年5月9日&#xff0c;中国计算机用户协会信息科技审计分会会员大会暨金融科技风险管理与审计论坛成功于北京召开。擎创科技CEO杨辰受邀与会&#xff0c;并分享了在数智运维发展过程中对企业数智化转型建设的规划思考以及相关实践经验。 同时&#xff0c;年会上举行了“金融…

《基础知识》提示学习的基本知识

《基础知识》提示学习的基本知识 提示学习背景提示的形式和元素提示学习的输入形式提示学习的重要元素提示学习的输入形式举例基本提示任务提示学习 内容参考:打工人转型之道(二):提示工程(Prompt Engineering)进阶篇

【服务器】利用树莓派搭建 web 服务器【无需公网IP】

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员&#xff0c;2024届电子信息研究生 目录 概述 使用 Raspberry Pi Imager 安装 Raspberry Pi OS 设置 Apache Web 服务器 测试 web 站点 安装静态样例站点 将web站点发布到公网 安装 Cpolar内网穿透 cpolar进行tok…

基于 FPGA 的彩色图像灰度化的设计实现(image_stitche_x)

文章目录 前言一、图像合并模块的设计二、仿真文件 前言 image_stitche_x 模块&#xff1a;将串口接收的尺寸为 400480 大小的彩色图像与灰度化处理后的 400480 大小的图像数据以左右形式合并成一张 800*480 的图像。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面…

AI再度升级,IT业一片哀鸿遍野:程序员真的要失业了吗?

IT人员真的要失业了吗&#xff1f; 随着各个大厂已经相继传来裁员&#xff0c;降薪&#xff0c;减招的消息和ChatGPT等大型AI模型可以定制化写参考代码&#xff0c;甚至通过外接API直接帮助操作&#xff0c;IT人员似乎越来越不吃香了。 其实&#xff0c;ChatGPT有用的不是取代…

Diango学习-用户管理系统(简单部门管理、用户管理)

目录 1、创建项目和app 1.创建项目 2.创建app 2种创建方式 注册app 2、表结构的创建 Django中的模型字段有很多种&#xff0c;包括但不限于&#xff1a; 设计表结构&#xff08;Django&#xff09; 在models.py文件中创建表&#xff1a;部门表和员工表 加入性别列&…

FL Studio21.0.3.3517完整试用版

系统要求 FL STUDIO 可以运行在任何计算机上: 支持 WINDOWS: 7, 8, 10 或者更高版本 支持 MacOS: 10.11 或更高版本 不低于 4GB 的可用硬盘空间 建议最低 4GB 内存或 更高 当然CPU 越强大&#xff0c;也就意味着你运行的音源和效果器越多! FL Studio是一个非常受欢迎的数…

轻松实现远程访问本地wamp服务器,无公网IP也不怕,「内网穿透」

目录 前言 1.Wamp服务器搭建 1.1 Wamp下载和安装 1.2 Wamp网页测试 2. Cpolar内网穿透的安装和注册 2.1 本地网页发布 2.2 Cpolar云端设置 2.3 Cpolar本地设置 3. 公网访问测试 4. 结语 转载自cpolar极点云的文章&#xff1a;无公网IP&#xff1f;教你在外远程访问本地…

新零售发展现状剖析

“新零售”的商业生态将涵盖网络页面、实体店面、支付终端、数据系统、物流平台和营销路径等诸多方面。 企业通过使用大数据和人工智能等先进技术升级产品的生产、流通和销售流程&#xff0c;重塑商业结构与生态圈&#xff0c;深度融合线上服务、线下体验和现代物流。将物流、…

Devexpress GridControl 内部调用外面实现的FocusedRowChanged

个人需求是网格自带的条件发生改变时&#xff08;网格显示的内容会发生改变&#xff09;&#xff0c;同时需要刷新另一个网格的数据源&#xff0c;而另一个网格的数据源是走的这个网格的行焦点改变事件去刷新&#xff0c;自带的条件发生改变时并不会触发行焦点的改变 当前情况…

【HTTP协议】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 1. HTTP协议概述 2. HTTP协议的工作过程 3.…

LabVIEWCompactRIO 开发指南21 使用TCP/IP时处理孤立套接字

LabVIEWCompactRIO 开发指南21 使用TCP/IP时处理孤立套接字 无法重新建立侦听TCP套接字是设计基于TCP/IP的应用程序时最常见的挑战之一。此症状是由终止客户端或服务器应用程序后发生的孤立套接字引起的。如果按照本节中所述的技术设计代码&#xff0c;则可以避免此问题。本节…

大数据拥抱云原生 HashData助力资管数字化转型

5月16日&#xff0c;2023国际资管科技创业者与投资者大会“资管数据处理&#xff08;大模型&#xff09;技术”专场在上海举行。本次大会以“资产管理 数智技术”为主题&#xff0c;邀请企业、高校、投资机构等各方开展产业交流与讨论&#xff0c;共享共创行业机遇。 酷克数据…

GPT-5: 超越人类语言的模型,你还不了解一下?

目录 一、GPT-5时代引领者 二、技术特性 1&#xff0c;音频和视频处理 — 更强大的多模态处理能力 2&#xff0c;GPT-5颠覆影视制作&#xff1a;重写媒体消费时代 3&#xff0c;为机器人提供智慧大脑 4&#xff0c;更强的垂直行业应用 三、回顾一下GPT5被紧急叫停&…

设计模式之【命令模式】,方法调用的花式玩法

文章目录 一、什么是命令模式1、命令模式使用场景2、命令模式的主要角色3、命令模式优缺点4、命令模式注意事项及细节 二、使用示例1、命令模式的一般写法2、播放器功能案例3、遥控器案例 三、源码中的命令模式1、Thread 一、什么是命令模式 命令模式&#xff08;Command Patt…

图像分割标注工具——QuPath使用说明

0、QuPath资源一览 QuPath是一款病理学和生物图像定量分析的软件&#xff0c;支持多种标注方式。一些常用资源如下&#xff1a; 官网&#xff1a;QuPath 官方文档&#xff1a;https://qupath.readthedocs.io/en/stable/docs/intro/index.html 软件下载列表&#xff1a;http…

搜狗主动推送工具-搜狗推送接口自动推送

想要让自己的网站被搜狗快速收录&#xff0c;以下是一些优化建议&#xff1a; 提交网站地图&#xff1a;将网站地图提交到搜狗搜索引擎&#xff0c;能够让搜索引擎更快速地爬取和发现网站所有的页面。同时在网站地图中应该包含网站所有页面的链接&#xff0c;方便搜狗搜索引擎爬…