C#代理多样性

一、代理

首先我们要弄清代理是个什么东西。别让一串翻译过来的概念把大家搞晕了头。
有的文章把代理称委托、代表等,其实它们是一个东西,英文表述都是“Delegate”。由于没有一本权威的书来规范这个概念,所以现在网上对它的称谓不一。本文我将以“代理”来称谓Delegate。
代理是什么呢?我认为“代理就是用来定义指向方法的引用”。下面我们就通过类来理解代理。
如:
Ren r = new Ren("车延禄");
上面的代码,就是使用Ren这个类定义了一个指“车延禄”这个对象实例的一个引用。
也可以这样理解:用Ren类定义的变量r,指向一个“车延禄”对象的实例。
类所定义的变量指向的是一个对象,代理所定义的变量指向的是个方法,当然这个方法可以是静态方法也可以是实例方法。对代理引用的调用就是对代理所指向方法的调用。
1.代理声明的语法:
[public/private] delegate <返回值类型> <代理名称>(<参数列表>);

[public/private]:访问修饰符。
delegate:代理声明关键定,相当于类声明的Class关键定
<返回值类型>:代理所指向的方法的返回值类型
<代理名称>:代理类型的名称
<参数列表>:代理所的指向的方法的参数列表。

要想使代理对象能够指向一个方法,那这个方法的要满足两个条件
a.方法返回类型要与delegate声明中的“返回值类型”一致。
b.方法的形参形表要与delegate声明中的“参数列表”一致。

如:
delegate void MyDelegate(string str,int index);
该代理声明表示:该代理指向的方法必须是返回空类型,并且拥有两个参数,第一个是字符串类型,第二个是整型。
2.代理“实例化”:
代理声明相当于类的定义。有了类的定义后我们要还需生成这个类的对象;同样有了代理的声明我们还需要“实例化”代理

如:MyDelegate md = new MyDelegate(Show);

这里的md就是代理变量。在代理的“实例化”的时候必须在构造函数中传入一个方法名。这个方法名就是该代理指向的方法,当然该方法的返回值类型与参数类型一定要与代理的声明一致。

Show方法定义如下:
public static void Show(string str, int index)
{
Console.WriteLine("Show"+str+index.ToString());
}
3.代理的调用:
md("hello world",22);
此时调用的就是md这个代理变量所指向的Show方法。
4.例子:
delegate void MyDelegate(string str,int index);    //声明代理
class Test
{
public static void Show(string str, int index)     //声明方法
{
Console.WriteLine("Show"+str+index.ToString());
}
public static void Main(string[] args)
{
MyDelegate md = new MyDelegate(Show); //1.实例化代理,传入方法
md("hello world",22);                                    //2.传入参数
}
}
5.代理的应用:
代理的主要应用就是在DotNet中的事件处理,所以要想研究事件我们必须要理解代理的概念。有的文章使用代理进行冒泡排序,我感觉这没必要,因为不用代理我也可以排序,更况且在C#语法中也不需要我们手动编写冒泡排序代码。
关于代理,大家要理解代理是个什么东西,并且能够写一个简单的代理示例就可以了。

二、多播代理
上面我们讲的代理是一个代理对象指向一个方法,在调用该代理对象的时候就会调用它所指向的方法。多播代理就是为一个代理挂接上多个方法,当执行该代理的时候就会依次执行该代理上挂接的方法。
1.多播代理的声明与上面讲得基本上一样:

[public/private] delegate void <代理名称>(<参数列表>);

只有一点不一样的就是,多播代理所指向的方法应当是void类型。
2.多播代理“实例化”
多播代理“实例化”与上面讲得一样,在此不多说了。

如:MyDelegate md = new MyDelegate(Show);

3.多播代理挂接多个方法。
多播代理可以使用 += 运算符挂接多个方法,也可以使用 -= 运算符从挂接列表中删除相应的挂接方法。

如:
delegate void MyDelegate(string str,int index);
class Test
{
public static void Show(string str, int index)
{
Console.WriteLine("Show"+str+index.ToString());
}
public static void TestInt(string str, int index)
{
Console.WriteLine("Testint");
}
public static void Main2(string[] args)
{
MyDelegate md = new MyDelegate(Show);  //传入方法
md += new MyDelegate(TestInt);                   //传入另一个方法
md("hello world",22);
}
}
在上面这个例子当中有两个方法(Show和TestInt)符合MyDelegate代理的签名,如果要把这两个方法挂接到我们一个代理变量上去的话,就得用 += 运算符了。
MyDelegate md = new MyDelegate(Show);
md += new MyDelegate(TestInt);
这里的md代理变量上先挂接了Show方法,再挂接TestInt方法。当执行md("hello world",22)的时候会先调用Show方法,再调用TestInt方法。
事件本身就是一种多播代理

    三、事件:    1.用执行事件传入参数     2.用注册事件传入方法
C#中的事件就是代理的一个变量。它和属性、方法一样,都是类的成员。只不过事件是指向一个方法,当事件被触发时,就会执行对象的相关方法。
事件的这种对方法的引用并不是写死在代码里面的,而是可以进行更改的。辟如:我们在DotNet中按钮的OnClick事件,它可以指向符合OnClick事件签名的任何一个方法。
1.事件的定义使用event关键字:
public event CryHandler DuckCryEvent;

其中的CryHandler是一个delegate。从上面的代码我们可以看出来:事件就是一个代理类型的变量。
private delegate void CryHandler();
2.指定事件处理程序:
指定事件处理程序就是为事件挂接方法的过程。
DuckCryEvent +=new CryHandler(Cry);   //注册事件,传入方法
public void Cry()
{
Console.WriteLine("我是一只小鸭,呀依呀依呀....");
}

3.执行事件
执行事件就是调用事件所指向方法的过程。一般对事的执行代码写在相应的方法或属性中,如果方法或属性被调用时就触发事件。
public void BeShaked()
{
DuckCryEvent();
}

4.完整的例子:
//事件用到的代理,以般以×××Handler的格式进行命名
private delegate void CryHandler();             //无参代理
//玩具小鸭的类
class Duck
{
  //定义小鸭的唱歌事件
public event CryHandler DuckCryEvent;
public Duck()
{
  //把小鸭唱歌的事件挂接到Cry方法上
DuckCryEvent +=new CryHandler(Cry); //注册事件,传入方法
}
//小鸭唱歌事件对应的处理方法
public void Cry()
{
Console.WriteLine("我是一只小鸭,呀呀呀....");
}
//小鸭被摇动
public void BeShaked() //执行方法,引发cry事件
{

DuckCryEvent();                                  //执行事件,传入参数
}
}
class Class2
{
public static void Main3(string[] args)
{
  //买一只小鸭
Duck d = new Duck();
//摇一摇小鸭,它就会调触发小鸭的Cry事件,小鸭就会唱歌
d.BeShaked();
}
}
   四、注意事项

C#中的delegate和C++中的函数指针基本是一回事,C#正是以delegate的形式实现了函数指针。不同的地方在于C#中delegate是类型安全的并且完全面向对象的。

Delegate 与C++相比优点:

A、函数指针只能指向静态函数,而delegate既可以指向静态函数也可以指向非静态成员函数。

B、与函数指针相比,delegate 是面向对象、类型安全、可靠的受控对象,runtime 能够保证delegate 指向一个有效的方法,不须担心delegate指向无效地址或是越界地址。

 

要理解Delegate,首先,你要明白,它是一个类,他和Class是一个级别的概念,不同在于Class的定义包含字段和方法,而delegate只包含方法的细节。Delegate 类能够拥有一个签名(signature),并且它只能持有与他的签名相匹配的方法的引用。


(1)在C#中,所有的代理都是从System.Delegate类派生的(delegate是System.Delegate的别名)。

(2)代理隐含具有sealed属性,即不能用来派生新的类型。

(3)代理最大的作用就是为类的事件绑定事件处理程序。

(4)在通过代理调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。

(5)在代理实例中可以封装静态的方法也可以封装实例方法。

(6)在创建代理实例时,需要传递将要映射的方法或其他代理实例以指明代理将要封装的函数原型(.NET中称为方法签名:signature)。注意,如果映射的是静态方法,传递的参数应该是类名.方法名,如果映射的是实例方法,传递的参数应该是实例名.方法名。

(7)只有当两个代理实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。

(8)多个代理实例可以形成一个代理链,System.Delegate中定义了用来维护代理链的静态方法Combion,Remove,分别向代理链中添加代理实例和删除代理实例。

(9)代理三步曲:
           a.声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型:   delegate int MyDelegate();
           b.创建delegate对象,并将你想要传递的函数作为参数传入:

                    MyDelegate d = new MyDelegate(MyClass.MyMethod);
          c.在要实现异步调用的地方,通过上一步创建的对象来调用方法。using System;

                       int ret = d(); 

          五、托管函数

                   1、什么是托管函数?

                            托管函数是一个对类里面的某个函数的一个引用。它子并没有具体的函数定义,只是指向某个函数实现。

                  2、托管函数有什么作用?

                     由于托管函数是对类里面某个函数的一个引用.所以我们不必知道这个函数的具体名字是什么,而只需要调用托管函数,让托管函数去调用相应的函数就可以了. 一个例子: 一个公司,一个领导,一个领导秘书,三个员工分别管理市场,策划和生产.这里秘书就相当与一个托管函数, 领导要下达什么命令(获得市场信息,生产什么产品),只需要对秘书说给我一份市场报告或者我们不生产原子弹转向生产氢弹.然后再由秘书根据领导的命令选择的去找哪个员工,再把员工获得的信息返回给领导. 这里面三个员工对于领导是透明的,领导并不知道自己下达的命令具体是由谁执行的.

示例: //给秘书下达命令执行

public void ExecuteCommand(string command)

{  switch(秘书根据命令判断是要给谁执行的)

{  // 这里的实现类似于某种设计模式

case 调研市场的人:

Doit=new Do(new MarketMan().GetMarketInfo);Break;

Case 生长产品的人:

Doit=new Do(new ProductMan().ProduceProduct);Break;

     Default: Break;

 }

}

转载于:https://www.cnblogs.com/w-wfy/p/7227735.html

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

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

相关文章

AMD 和 Intel 之战:CPU 哪家强?

来源&#xff1a;嵌入式资讯精选作者 | Paul Alcorn译者 | 弯月&#xff0c;责编 | 郭芮以下为译文&#xff1a;不论是选游戏CPU还是桌面应用的CPU&#xff0c;我们只有两种选择&#xff1a;AMD或者英特尔。两家都有各自的粉丝&#xff0c;所以想买CPU的人很难获得中肯的建议&a…

issubclass在python中的意思_python基础之类的isinstance与issubclass、反射

一 isinstance(obj,cls)和issubclass(sub,super)isinstance(obj,cls)检查是否obj是否是类 cls 的对象class Foo:passobj Foo()print(isinstance(obj,Foo))issubclass(sub, super)检查sub类是否是 super 类的派生类class Foo:passclass Bar(Foo):passprint(issubclass(Bar,Foo)…

华为的汽车芯片布局

来源&#xff1a;电子发烧友综合报道&#xff0c;内容参考自雷锋网、IT之家、CnBeat&#xff0c;转载请注明以上来源由于政策扶持&#xff0c;新能源汽车发展迅速&#xff0c;华为也开始进军新能源汽车市场&#xff0c;最近动作频繁&#xff0c;例如联合意法半导体研发汽车芯片…

Linux - which xxx - 查找执行的命令所在的路径

Linux 下&#xff0c;我们常使用 cd ,grep,vi 等命令&#xff0c;有时候我们要查到这些命令所在的位置&#xff0c;如何做呢&#xff1f; Linux 下有2个命令可完成该功能&#xff1a;which ,whereis which 用来查看当 前要执行的命令所在的路径。 whereis 用来查看一个命令或者…

java 数据库 事务 只读_java – odd SQLException – 无法检索转换只读状态服务器

我有一个Quartz作业&#xff0c;每5分钟一次在MySQL数据库中执行一个存储过程&#xff0c;由于某种原因&#xff0c;3个执行中有1个失败&#xff0c;并提供了这个奇怪的异常。我搜索并搜索了这个异常是什么意思&#xff0c;但是我找不到解决方案。这是完整的堆栈跟踪&#xff1…

【转】JMeter学习(二十七)Jmeter常见问题

收集工作中JMeter遇到的各种问题1. JMeter的工作原理是什么&#xff1f;向服务器提交请求&#xff1b;从服务器取回请求返回的结果。2. JMeter的作用&#xff1f;JMeter可以用于测试静态或者动态资源的性能&#xff08;文件、Servlets、Perl脚本、java对象、数据库和查询、ft…

大热下的 GNN 研究面临哪些“天花板”?未来的重点研究方向又在哪?

作为脱胎于图论研究的热门研究领域&#xff0c;图神经网络&#xff08;GNN&#xff09;与经典的 WL 算法有诸多相似之处。众所周知&#xff0c;强大的 WL 算法对于聚合函数的单射性质有很强的要求&#xff0c;那么强大的 GNN 应该具备哪些性质呢&#xff1f;研究大热下&#xf…

java将一个对象赋值给另一个对象_java一个对象赋值给另一个对象,支持平铺类和层级类间的互转...

场景&#xff1a;将一个层级类对象(领域驱动model对象)转换为平铺类对象(view)src对象&#xff0c;(红框为子对象)target对象(平铺对象)代码思路&#xff0c;先递归反射遍历出所有字段&#xff0c;存到一个map里&#xff0c;再递归赋值给target对象缺陷&#xff1a;不同子对象间…

HTML中关于图像和表格,链接等的知识

下面是我分享的html中关于图像和表格&#xff0c;链接等知识&#xff1a; ①<img/>图像标签 <img/>标签中的一些常见属性&#xff1a;1&#xff0c;src是图像的路径属性&#xff0c;是img标签中必不可少的属性。 2&#xff0c;alt是代表当图像显示失败时代替图像的…

新基建的内涵、意义和隐忧 ,基于互联网大脑模型的分析

2020年4月20日上午&#xff0c;国家发改委召开4月份例行新闻发布会&#xff0c;首次就“新基建”概念和内涵作出正式的解释。“新型基础设施是以新发展理念为引领&#xff0c;以技术创新为驱动&#xff0c;以信息网络为基础&#xff0c;面向高质量发展需要&#xff0c;提供数字…

丑数

问题描述&#xff1a;我们只把包含因子2、3和5的数称为丑数。求按从小到大的顺序的第1500个丑数。 分析&#xff1a;要找到第i个丑数&#xff0c;需要用辅助数组存储前面i-1个丑数&#xff0c;用空间换取时间。 package com.wyl; /*** 求丑数* 问题描述&#xff1a;我们只把包含…

jssdk分享设置_JSSDK自定义分享

web&#xff1a;1、引入JS文件&#xff1a;http://res.wx.qq.com/open/js/jweixin-1.4.0.js(支持https)http://res2.wx.qq.com/open/js/jweixin-1.4.0.js (支持https)2、获取签名等参数wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来&…

罗兰贝格84页白皮书:一文看懂中国ICT产业新黄金十年

来源&#xff1a;智东西中国信息和通信技术产业&#xff08;下称“ICT产业”&#xff09;蓬勃发展的黄金三十年&#xff0c;展现出了强大的市场吸引力与发展潜能。从上个世纪九十年代至今&#xff0c;ICT产业收入规模增长了340倍&#xff0c;保持双位数增长&#xff0c;领先全球…

Python之旅Day8 socket网络编程

socket网络编程 Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”&#xff0c;而打开一个Socket需要知道目标计算机的IP地址和端口号&#xff0c;再指定协议类型即可。socket服务一般分为服务端和客户端&#xff1b;与此同时&#xff0c;socke…

2020年五大虚拟现实和增强现实趋势

来源&#xff1a;AR工业应用2019年是VR/AR增长的一年&#xff0c;用户戴上VR头显就可以沉浸在计算机生成的环境中&#xff0c;VR在设计、营销、教育、培训和零售领域都有大量的需求。AR则通过屏幕或头显将计算机图像叠加到用户的真实世界视图上&#xff0c;预计2020年全球在XR技…

【实战练习】通过docker部署jenkins

jenkins官网 &#xff1a;https://jenkins.io/拉取jenkins Official Jenkins Docker image[rootip-172-31-16-58 ec2-user]# docker pull jenkins/jenkinsUsing default tag: latestlatest: Pulling from jenkins/jenkins06b22ddb1913: Pull complete336c28b408ed: Pull comp…

linux hive mysql_Linux下的Hive与Mysql安装

一&#xff0c;安装MySQLsudo apt-get install mysql-server mysql-client1). 建立数据库hive&#xff0c;create database hive;2). 创建用户hivecreate user ‘hive’’%’ identified by ‘hive’;3).创建hive用户,并授权grant all on hive.* to hive’%’ identified by ‘…

当AI实现多任务学习,它究竟能做什么?

来源&#xff1a;脑极体提到AI领域的多任务学习&#xff0c;很多人可能一下子就想到通用人工智能那里了。通俗意义上的理解&#xff0c;就像《超能陆战队》里的大白这样一种护理机器人&#xff0c;既能进行医疗诊断&#xff0c;又能读懂人的情绪&#xff0c;还能像陪伴机器人一…

mysql sql先后执行_MySQL中SQL语句执行顺序

(7) SELECT(8) DISTINCT (1) FROM (3) JOIN(2) ON (4) WHERE (5) GROUP BY (6) HAVING (9) ORDER BY (10) LIMIT 前期准备工作1、新建一个测试数据库create database testData;2、创建测试表,并插入数据如下&#xff1a;用户表订单表准备SQL逻辑查询测试语句SELECT a.user_id,C…

《自然》:欧洲根据已知基因序列合成新冠病毒,助力疫苗开发

来源&#xff1a;澎湃新闻当地时间5月4日&#xff0c;国际顶级学术期刊《自然》&#xff08;Nature&#xff09;以“加快评审文章”(Accelerated Article Preview)形式在线发表了来自瑞士、德国、俄罗斯多家科研机构的一项研究“Rapid reconstruction of SARS-CoV-2 using a sy…