表面上看来使用delegate是一件很简单的事。

用delegate关键字定义,使用老套的new创建一个instance ,使用熟悉的方法调用写法调用,只不过不在是方法名,而是委托名。
但是在这背后CLR为我们做了很多。
 
当我们 写下下面这句话时
 
public delegate void FeedBack(Int32 val);
 
其实相当于 大概下面的代码(省略部分多线程相关代码)
 
pubic class FeedBack:MulticastDelegate
{
  public FeedBack(Object  object ,  IntPtr  methodPtr)
  {
   xxxx
  }
  public virtual void Invoke(int32 val);
}
 
首先delegate 就是一个class。这个class会自动继承MuticastDelegate .然后,这个class 的构造函数就如上面所示, 
我们先看第二个参数 methodPtr  可以理解为函数的指针,或者说函数的地址。委托在真正运行的时候,就要找到这个函数的地址,并运行这个函数。对,我们要先找到这个函数的地址,对于 static类型的函数,地址是确定的,而对于实例函数而言,内部的函数地址则是不定的,它需要先确定具体的某个实例, 这既是第一个参数的用途,具体实例的引用,对于static类型的函数,就会默认传入一个null。
其实,在基类 MutiCastDelegate中,有三个重要的非公开属性
 
_target 
_methodPtr
_invokationlist
 
一二两个属性 刚好对应我们构造函数传入的两个参数,第三个属性和委托链有关,默认为null,我们先不讨论。
 
也就是说:delegate 其实只是个wrapper ,包装着需要真正操作的对象 以及它的方法。
 
也就是说委托的构造函数 完成了 和具体真实对象以及真实方法的对应,而调用则是另一个方法 Invoke(int32 val)。这个方法会触发真实方法的调用。
 

关于委托链式。。。我就不深究了,因为实在比较懒。。
可以理解为 一个delegate数组一次存放着这些委托,然后调用的时候,内部通过foreach一个一个调用。。.也就造成了整个委托链中的方法都被调用的 “链式反应”。因为内部实现也就是数组,所以 具体调用次序是确定的,而不是随机的,根据的加入委托链中的顺序会依次调用这些方法。
如何拼成一个委托链,有两种写法
 
在早期版本中 通过 Delegate.Combine 静态方法来拼接链,(每次拼接要记得赋给原先的链)。就像现实生活中装链条一样,有两个参数,第一个参数是 已装的部分链,第二个参数是待装的。(链子的内部是依靠数组实现的)
 
第二种写法,是C#为了更好的辅助delegate而 自动对+= 和-=这两个操作符提供了重载。也就是说delegate实例之间可以简单的通过
+=和-=来拼接。这无疑相当大的简化了 委托链。(至于怎么重载的,因为懒。。就不模拟了。)
 
拼完委托链之后,只需要直接调用委托一样调用委托链即可,委托内部的算法会依次调用每个拼接的元素。但有一个缺憾就是,如果委托是带有返回值的,那么只能返回最后一个委托执行的返回值前面所有委托的返回值都会被丢弃。
有什么办法呢,如下。

委托链的高级调用
 
如上所说,如果直接invoke委托链的话,那么只有链尾的返回值会输出出来,并且简单直接的链式调用还有巨大的隐患,如果其中的某个delegate抛出异常,那整个链都会卡住   。如果想要的每一个委托的返回值,就不能用上面的方法。
 

委托与泛型
 
我们先定义一个委托
 
public void FeedBack(Int32 value);
 
然后我们又突然需要另一个委托。。o(╯□╰)o
 
public void FeedBack(string value)
 
可以这样来定义吗? ,绝对不可以!!委托的本质是class 所以你上面的做法只是重复定义了同名的类罢了。
 
委托可以融入泛型来更加强大   ,看下面的完整实例
 

 public delegate void FeedBack <T>(T para);
public delegate void FeedBack<Tint,Tstr>(Tint para1,Tstr para2);
class 委托可以有泛型吗
{
public static void Main(string[] args)
{
FeedBack<Int32 > fb = new FeedBack<int >(FeedBackInt);
FeedBack<String > fb2 = new FeedBack<string >(FeedbackString);
FeedBack<int ,string > fb3 = new FeedBack<int , string >(FeedbackIntString);
fb.Invoke();
fb2.Invoke( "haha");
fb3.Invoke(,"haha" );
Console.ReadKey();
} public static void FeedBackInt(Int32 val)
{
Console.WriteLine(val);
}
public static void FeedbackString(String str)
{
Console.WriteLine(str);
}
public static void FeedbackIntString(int val,string str)
{
Console.WriteLine(val+":" +str);
}
}
}
 
不知道看到这里,你心里会不会隐隐约约有一种想法。。。。那就是微软所想到的:通过泛型可以把你编程几乎会用到的所有可能的委托囊括!!!!
他们确实这样做了。。这就是FCL 拥有的自建委托。不带返回值的统称  Action  带返回值的统称  Func. 自带委托如下,参数最多
上限16个。再多的话,这个方法本身就很有问题了。
 
 
以及
 
微软建议,在需要使用委托的时候就是用内建的这些委托,而不要再去自己创建委托类型了。那我们就遵守这个惯例吧。
当然 也有可能这些泛型不符合你需要的委托。 比如你需要这个
delegate void bar(ref  int32 z);  ,或者说你的泛型委托需要一些约束。那就得自己定义委托了。。
 
 

最常见的delegate的用途应该是webform中的事件处理机制。
我们常常会见到这样的写法:
button1.Click += button1_Click;
 
void button1_Click(Object sender, EventArgs e) {
// Do something, the button was clicked...
}
 
在学习的时候竟然很少有人对这种写法感到诧异。。 这是C# 提供的语法糖。
正常的写法是 button1.Click += new EventHandler(button1_Click);
现在认识么? 就是简单的拼接 delegate 链而已╮(╯_╰)╭。  上面的语法糖是委托里的第一种语法糖。
在需要委托实例的地方 不再需要委托实例,直接提供委托要包含的的函数名即可。
 
(events 是更安全的delegate .实际上是使用自建的EventHandler委托,然后,每次触发不同控件的时候,会通过EventHandler(sender,e)) 这个委托来触发实际的方法。
 
ok 委托先到这里。
 
 

Delegate背后的秘密的更多相关文章

  1. 增强学习 | AlphaGo背后的秘密

    "敢于尝试,才有突破" 2017年5月27日,当今世界排名第一的中国棋手柯洁与AlphaGo 2.0的三局对战落败.该事件标志着最新的人工智能技术在围棋竞技领域超越了人类智能,借此 ...

  2. 5.JavaScript优化及导航菜单背后的秘密

    JavaScript优化及导航菜单背后的秘密 伍星 学习目标1.进一步了解前端优化 学习如何编写良好的 JavaScirpt2.通过导航的学习,了解JavaScirpt的应用 JavaScript在用 ...

  3. 隐藏在QRCode二维码背后的秘密

    原文:隐藏在QRCode二维码背后的秘密 隐藏在QRCode二维码背后的秘密,您知道吗? 1.容错级. 二维码的容错级分别为:L,M,Q和H.其中,L最低,H最高.如何从二维码中一眼看出其容错级别呢? ...

  4. 订单突破10000+,仅花1小时,APPx独家深入剖析背后的秘密!

    拼多多:成立三年,获客三亿,月订单成交额达到恐怖的400亿,成功上市! 糕妈优选:营销活动推送1小时,订单超过10000+,商品成功刷屏朋友圈! 寻慢:一场活动净增7000+粉丝,付款转化率高达71% ...

  5. UF2.0、O4、UFT、TA众明星背后的秘密

    UF2.0--经纪业务运营平台 O4--投资交易管理系统软件 UFT--证券极速交易系统软件 TA--登记过户系统 -- 说到恒生在业内的明星产品,太多了,小编一口气说不完,但小编只知其一,殊不知这些 ...

  6. 【原创】http请求中加号被替换为空格?源码背后的秘密

    这是why技术的第**20**篇原创文章![在这里插入图片描述](https://user-gold-cdn.xitu.io/2019/12/30/16f550eb82e10eff?w=900& ...

  7. 拇指记者深入Android公司,打探事件分发机制背后的秘密

    前言 聊到事件分发,很多朋友就会想到view的dispatchTouchEvent,其实在此之前,Android还做了很多工作. 比如跨进程获取输入事件的方式?在dispatchTouchEvent责 ...

  8. ASP.NET Core 2.0 : 七.一张图看透启动背后的秘密

    为什么我们可以在Startup这个 “孤零零的” 类中配置依赖注入和管道? 它是什么时候被实例化并且调用的? 参数中的IServiceCollection services是怎么来的? 处理管道是怎么 ...

  9. 让你的代码量减少3倍!使用kotlin开发Android(四) kotlin bean背后的秘密

    上一篇我们介绍了缩短五倍的java bean,不知道你在看的时候有没有一种疑问捏? 本文同步自博主的私人博客wing的地方酒馆 再来回顾一下,两种代码的对比 public class User { p ...

随机推荐

  1. sublime text 显示 typescript高亮

    用ionic angular2写东西,还是用我的sublime 发现ts文件不识别,没有高亮.搜呗. 搜索出来的博客地址:http://www.cnblogs.com/happen-/p/638553 ...

  2. 爬虫实战3:使用request,bs4爬动态加载图片

    参考网站:https://blog.csdn.net/Young_Child/article/details/78571422 在爬的过程中遇到的问题: 1.被ban:更改header的User-Ag ...

  3. 本机号码认证黑科技:极光(JG)开发者服务推出“极光认证”新产品

    近日,中国领先的大数据服务商极光(JG)推出全新产品--极光认证JVerification.极光认证是极光针对APP用户注册登陆,二次安全验证等身份验证场景打造的一款本机号码认证SDK,验证用户提供的 ...

  4. Python标准库中的生成器函数

    一.用于过滤的生成器函数 - 从输入的可迭代对象中产出元素的子集,而不修改元素本身 import itertools l1 = [1,2,3,4,5] l2 = [True,False,True,Fa ...

  5. openproject安装与使用

    思路: 1.生成config配置文件 2.导出配置文件,修改配置文件,删除容器,重新部署容器 3.登录后配置, 4.配置git,可以从openproject里查看gitlab上的代码库 第一次安装: ...

  6. QuantLib 金融计算——数学工具之数值积分

    目录 QuantLib 金融计算--数学工具之数值积分 概述 常见积分方法 高斯积分 如果未做特别说明,文中的程序都是 Python3 代码. QuantLib 金融计算--数学工具之数值积分 载入模 ...

  7. RDD转换成为DataFrame

    方式一: 通过case class创建DataFrames(反射) TestDataFrame1.scala package com.bky // 隐式类的导入 // 定义case class,相当于 ...

  8. Python 两种获取文件大小的方法

    import os r=os.path.getsize("/root/catbird1.stl") f=open("/root/catbird1.stl",&q ...

  9. 使用Java Servlet进行简单登录

    效果图 登录页面代码:login.html <%@ page language="java" contentType="text/html; charset=UTF ...

  10. rpm: error while loading shared libraries: libgcc_s.so.1: cannot open shared object file: No such file or directory解决办法

    不多说,直接上干货! 问题详情 [root@bigdatamaster app]# rpm -qa | grep gcc rpm: error : cannot open shared object ...