热点推荐

查看: 1328|回复: 9
收起左侧

[资料] 深入理解C#委托及原理

[复制链接]
  • TA的每日心情
    点赞
    4 小时前
  • 签到天数: 564 天

    连续签到: 2 天

    [LV.9]以坛为家II

    348

    主题

    1301

    帖子

    6284

    积分

    Rank: 9

    积分
    6284

    突出贡献优秀版主荣誉管理论坛元老切换助手验证会员最佳新人

    发表于 2017-11-1 21:09:31 | 显示全部楼层 |阅读模式

    51Halcon诚邀您的加入,专注于机器视觉开发与应用技术,我们一直都在努力!

    您需要 登录 才可以下载或查看,没有帐号?会员注册

    x
    一、委托
    设想,如果我们写了一个厨师做菜方法用来做菜,里面有 拿菜、切菜、配菜、炒菜 四个环节,但编写此方法代码的人想让 配菜 这个环节让调用方法的人实现,换句话说,就是想在方法被调用时接收代码 作为参数,在方法中执行这端传进来的代码。
    但,怎么为一个方法传 代码 进来呢?当然大家想到了传递接口方式来实现,咱先不讨论接口,因为微软为我们提供了一个叫做 【委托】 的类型。

    (一)、委托基础:
    1.       先看看代码:
    (1).定一个方法:void SayHi(string name){Console.WriteLine(“Hi~”+name+”! ” );}
    (2).声明一种委托类型:delegate void DGSayHi(string uName);
    (3).创建委托类型对象:DGSayHi dgObj = new DGSayHi(SayHi);//构造函数中传入了方法
    (4).执行委托:
    dgObj(“JamesZou”); //调用委托(奇怪:对象加括号 的方式调用?后面解释。)
    输出:Hi~JamesZou!

    2.       什么是委托?
    (1)概念:“C# 中的委托类似于 C 或 C++ 中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后调用该委托对象就可以执行委托对象内方法引用指向的方法,而不必在编译时知道将调用哪个方法(如参数为委托类型的方法,也就是提供了为程序回调指定方法的机制)。”-- 引自MSDN

    (2)通俗:就是一个能存放很多方法的指针的调用清单(但方法签名必须和委托类型签名一样),你一调用这个清单,那么清单里的所有的指针所对应的方法就会依次被执行。

    (3)比方说:有三台机器A、C、D,点一个红色按钮就会运行。操作人员接到指令,要求在接到电话后分别打开AD机器,然后然后工人就在接到电话后,先后打开AD机器。(此例中的 三台机器就是方法,操作员,就可以看成是“委托”啦)

    (4)概要图例:
    DGSayHi dgObj = new DGSayHi(SayHi);
    dgObj(“James”); //调用委托对象,就会执行委托对象里的方法。
    2011072110341081.jpg

    3.       委托有什么用?
    A.能够帮程序员在需要时,根据条件动态执行多个方法:(接上例代码)
    (1)定三个方法:
    void SayHi(string name){Console.WriteLine(“Hi~”+name ); }
    void DaZhaoHu(string name){ Console.WriteLine(“你好啊~”+name ); }
    string OHaUo(string name){ Console.WriteLine(“OHaUo ~”+name ); return “JapHi”;}

    (2)创建委托类型对象,并通过构造函数传参方式向委托对象“注册”第一个方法:
    DGSayHi dgObj = new DGSayHi(SayHi);

    (3)继续“注册两个方法”:
    dgObj+=DaZhaoHu;// (奇怪:对象之间用+=符号来操作?后面解释)
    //dgObj+=OhaUo;//注释此行代码,因为编译时报错,OhaUo方法签名与委托类型的签名不一致(委托签名无返回值)。

          (4)执行委托对象:
    dgObj(“James”); //执行了此委托中注册的两个方法
    输出:
    Hi~James
    你好啊~James
          
    (5)概要图例
    2011072110350855.jpg

    B. 委托作为方法参数(回调方法机制)
    (1).接上例代码,再定义一个方法:
    void DoTestDelegateFun(DGSayHi dgObj){dgObj(“钢铁侠”);}
    (2).调用此方法:
    DoTestDelegateFun(SayHi);//输出:Hi~钢铁侠(奇怪:竟然直接传方法了?后面解释)

          C.委托语法糖
             (1).注意到上面有3个地方我们都觉得“奇怪”:
            a.调用委托对象dgObj(“JamesZou”);
            b.向委托注册方法 dgObj+=DaZhaoHu;
                  c.将方法作为参数 DoTestDelegateFun(SayHi);
             这些用法其实都是FW为我们提供的简便语法(它们有个可爱的名字:语法糖),在编译时由编译器转成完整的代码:
            a. dgObj.Invoke(“JamesZou”);
            b. dgObj = (DGSayHi) Delegate.Combine(dgObj, new DGSayHi(this.DaZhaoHu));
    //Combine方法将第二个参数,添加到dgObj中,并返回委托对象。
    c. this.DoTestDelegateFun(new DGSayHi(this.SayHi));
             Delegate类、Invoke方法、Combine方法是哪来的呢?

    (二)、委托原理
    1.delegate 关键字
    (1).概念:delegate 关键字用于声明一个引用类型,该引用类型可用于封装命名方法或匿名方法。

    (2)编译后生成的的中间代码。
    请大家思考一下,关键字是类型吗?不是。那编译器遇到这个关键字做了什么事情?借助【IL反汇编程序】 我们来看一看:
    a.开始-程序-如图:
        2011072110355247.jpg
    b.打开项目文件夹下的binDebug文件夹,找到程序集 CodeForFun.exe,拖入到【IL反汇编程序】界面中便可看到程序集的IL代码:
    找到我们定义了委托DGSayHi的类DelegateForFun,发现,里面的 委托类型声明 代码
    编译前:delegate string DGSayHi(string uName);
    变成了一个类:
        2011072110363250.jpg

    单击展开后我们再来看看:
    2011072110364173.jpg
       看出什么了?
    (I).继承了System.MulticastDelegate。
    (II).包含了构造方法、BeginInvoke、EndInvoke、Invoke方法。
    也就是说此时,delegate代码已经编译成了如下代码:
    编译后:
    class DGSayHi:System.MulticastDelegate
    {
      public DelegateForFun();
         void Invoke(string value);
         IAsyncResult BeginInvoke(string value,AsyncCallback callback,Object object);
         void EndInvoke(IAsyncResult result);
    }

    (3)System.MulticastDelegate 类
    下面我们来看看借助.Net Reflector工具来查看类库中的 MulticastDelegate 类
    public abstract class MulticastDelegate : Delegate
    由此我们可以看出继承关系:DGSayHi –> MulticastDelegate–> Delegate
    MulticastDelegate类中有3个重要的成员,其中两个继承自 Delegate  :
    2011072110365426.jpg
    a.三者的作用:
    _methodPtr 里保存的就是 方法指针。
    _target 里用来保存方法所在的对象。
    _invocationList 其实使用时是个object数组,在注册多个方法时,其他方法就保存在此成员中,而它也就是 委托链 的关键容器。
    b.概要图:
    2011072110372685.jpg
              图中的委托对象 dgObj 在创建时创建了指向方法 SayHi的指针并保存在 _methodPtr中;_target中保存了SayHi方法所在的类的对象(比如我把这段代码写在窗体里按钮的点击方法中,那么此时 _target就是 SayHi方法所在的窗体对象);_invocationList 中保存了追加的两个方法的指针,但这两个方法指针都是分别被装在 MuticastDelegate对象中。

    无效附件更新 权限提升操作 删帖申请 举报以及其他需要帮助请加入QQ群:214663141 广告位招商 有意者联系
  • TA的每日心情
    害羞
    2018-9-6 09:34
  • 签到天数: 89 天

    连续签到: 1 天

    [LV.6]常住居民II

    1

    主题

    32

    帖子

    623

    积分

    Rank: 6Rank: 6

    积分
    623
    发表于 2017-11-2 09:41:36 | 显示全部楼层
    朱大爷厉害!666666666666666666666

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

  • TA的每日心情
    叹气
    昨天 17:56
  • 签到天数: 394 天

    连续签到: 3 天

    [LV.9]以坛为家II

    27

    主题

    186

    帖子

    1535

    积分

    Rank: 7Rank: 7Rank: 7

    积分
    1535

    活跃会员优秀版主切换助手验证会员

    发表于 2018-2-1 15:37:15 | 显示全部楼层
    谢谢楼主,好东西,一起学习下

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

  • TA的每日心情
    害羞
    2018-9-6 17:56
  • 签到天数: 35 天

    连续签到: 1 天

    [LV.5]常住居民I

    0

    主题

    23

    帖子

    97

    积分

    Rank: 6Rank: 6

    积分
    97
    发表于 2018-2-24 09:42:50 | 显示全部楼层
    厉害了管理员,这么底层的东西!

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

  • TA的每日心情
    窃喜
    2019-2-13 11:09
  • 签到天数: 6 天

    连续签到: 2 天

    [LV.2]偶尔看看I

    0

    主题

    23

    帖子

    77

    积分

    Rank: 1

    积分
    77
    发表于 2018-5-2 17:26:38 | 显示全部楼层
    谢谢楼主,涨知识了

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

  • TA的每日心情
    害羞
    2018-5-7 22:22
  • 签到天数: 10 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    0

    主题

    6

    帖子

    443

    积分

    Rank: 6Rank: 6

    积分
    443
    发表于 2018-5-7 22:23:32 | 显示全部楼层
    朱大爷666

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

    该用户从未签到

    0

    主题

    4

    帖子

    56

    积分

    Rank: 1

    积分
    56
    发表于 2018-6-15 16:59:26 | 显示全部楼层
    好!!!!!

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

    该用户从未签到

    0

    主题

    4

    帖子

    88

    积分

    Rank: 1

    积分
    88
    发表于 2018-8-6 09:08:52 | 显示全部楼层
    讲的真的很透彻,楼主的研究方法和研究精神,真的令人佩服。

    发帖求助前要善用论坛搜索功能,那里可能会有你要找的答案;

    如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题前面加上【已解决】

    回报帮助你解决问题的坛友,右下角【免费评分】赠与对方视觉币和热心值,伸手党遭人唾弃,做一个热心并受欢迎的人!

    您需要登录后才可以回帖 会员登录 | 会员注册

    本版积分规则

    经营性网站备案信息 经营性网站
    备案信息

    中国互联网举报中心 中国互联网
    举报中心

    中国文明网传播文明 中国文明网
    传播文明

    诚信网站

    深圳市市场监督管理局企业主体身份公示 工商网监
    电子标识