• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > C#中委托的进一步理解

C#中委托的进一步理解

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c#委托,c#委托和事件,c#委托的用法,c#委托的作用,c#委托实例等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

前面一篇文章介绍了委托的基本知识,接下来就进一步研究一下委托。

委托类型

其实,刚开始觉得委托类型是一个比较难理解的概念,怎么也不觉得下面的"AssembleIphoneHandler"是一个类型。
public delegate void AssembleIphoneHandler();
</div>
按照正常的情况,如果我们要创建一个委托类型应该是:
public class AssembleIphoneHandler : System.MulticastDelegate
{
}
</div>
但是,这种写法是编译不过的,会提示不能从"System.MulticastDelegate"派生子类。

其实,这里是编译器为我们做了一个转换,当我们使用delegate关键字声明一个委托类型的时候,编译器就会按照上面代码片段中的方式为我们创建一个委托类型。

知道了这些东西,对于委托类型的理解就比较容易了,通过delegate声明的委托类型就是一个从"System.MulticastDelegate"派生出来的子类。

建立委托链

下面我们通过一个例子来看看委托链的建立,以及调用列表的变化,基于前面一篇文章中的例子进行一些修改。

class Program
{
    static void Main(string[] args)
    {
        Apple apple = new Apple();
        Foxconn foxconn = new Foxconn();

        Apple.AssembleIphoneHandler d1, d2, d3, d4 = null;
        d1 = new Apple.AssembleIphoneHandler(foxconn.AssembleIphone);
        d2 = new Apple.AssembleIphoneHandler(foxconn.PackIphone);
        d3 = new Apple.AssembleIphoneHandler(foxconn.ShipIphone);

        d4 += d1;
        d4 += d2;
        d4 += d3;

        d4();

        Console.Read();
    }
}
</div>

我们接下来进行一下单步调试看看委托链建立的过程。

1. 当下面三句执行完成后,可以通过VS看到d1、d2和d3的详细信息
d1 = new Apple.AssembleIphoneHandler(foxconn.AssembleIphone);
</div>

d2 = new Apple.AssembleIphoneHandler(foxconn.PackIphone);
</div>

d3 = new Apple.AssembleIphoneHandler(foxconn.ShipIphone);
</div>

对于上面三个委托实例来说:

1.调用列表为空,所以_invocationCount为0,_invocationList为空
2._target代表创建委托实例的方法来自Foxconn的实例;如果是静态方法创建的委托实例_target值为null
3._methodPtr代表这个方法的唯一标识,可以理解为句柄
4._methodBase包含创建委托实例的方法的信息,方法名、返回类型等等

2. 通过"+="操作符来进行委托合并
d4 += d1;
</div>

这时,由于d4初始值为null,在使用"+="操作(Combine方法)构造委托链时,将返回另外一个参数d1,再将d1的引用赋给d4(通过"ILSpy"查看,如下图)。也就是说,这时d4将指向d1所指向的对象。

3. 继续执行委托合并,并查看d4的变化

d4 += d2;
</div>

这时可以看到调用列表的变化,_invocationList包含两个元素,分别是d1和d2.

4. 最后进行一次委托合并,把d3合并到d4中
d4 += d3;
</div>

可以看到最新的d4实例中,调用列表已经包含了d3。

注意:由于委托是不可变的,所以这里应该描述为,d3和d4的Combine 产生了一个新的委托实例,新的委托实例的调用列表是d3和d4的合并;操作完成后,d4变量将指向新的委托实例的引用。

疑问:其实在这步调试过程中有个疑问,_invocationCount的值是3,但是_invocationList中有四个元素,最后一个为null,找了一下也没发现为什么,望高手看到帮忙解答。

所以对委托链建立的方法Delegate.Combine(Delegate A, Delegate B),可以进行下面的概括:

1.如果A和B均为null,则返回null。
2.如果A或B一个为null而另一个不为null,则返回不为null的委托。
3.如果A和B均不为null,返回一个新的委托(委托是不可变的),该委托_invocationList字段为一个委托数组,该数组中委托的顺序为:A中_invacationList所指向的委托数组 + B中_invacationList所指向的委托数组。

移除委托链

我们可以通过Delegate类的静态方法Remove,从一个委托链中移除一个委托,这里就不做演示了。

注意:当调用Remove时,会遍历(倒序)第一个参数中的中的调用列表(_invocationList), 找到与第二个参数的_target和_methodPtr字段相匹配的委托,并将其从委托列表中移除。

当有多个匹配的情况是,Remove方法只移除第一个匹配的委托;但是,可以通过RemoeAll方法来移除所有匹配的委托。

同样对委托移除的方法Delegate.Remove(Delegate A, Delegate B),可以进行下面的概括:

1.如果A为null,返回null。
2.如果B为null,返回A。
3.如果A的_invocationList为null,即不包含委托链,那么如果A本身与B匹配,则返回null,否则返回A。
4.如果A的_invocationList中不包含与B匹配的委托,则返回A。
5.如果A的_invocationList中包含与B匹配的委托,则从链表中移除B,然后
6.如果A的链表中只剩下一个委托,则返回该委托。
6-1).如果A的链表中还剩下多个委托,将重新构建一个新的委托,并且新的委托的_invocationList为A的6-2)._invocationList移除了B之后的List。

总结

通过这篇文章,进一步认识了委托类型,然后通过一个例子观察了委托链的建立以及调用列表的变化。

通过这两篇文章,对委托应该有了一定的认识:

1.通过delegate关键字声明委托类型

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C#中的委托使用
  • C#事件用法实例浅析
  • C#可空类型用法分析
  • C#中委托用法实例分析
  • C#委托现实示例分析
  • C#中委托的进一步理解
  • C#中委托的+=和-=深入研究
  • C#中的集合用法分析
  • C#中委托和事件的区别实例解析
  • C#中事件的继承实例分析

相关文章

  • 2017-05-28C#实现移除字符串末尾指定字符的方法
  • 2017-05-28C#实现任意数据类型转成json格式输出
  • 2017-05-28C#中timer类的用法总结
  • 2017-05-28C# 调用 JavaWebservice服务遇到的问题汇总
  • 2017-05-28.net的序列化与反序列化实例
  • 2017-05-28C#中简单的装箱操作实例分析
  • 2017-05-28C#实现从windows剪贴板获取内容的方法
  • 2017-09-12C#类概念介绍
  • 2017-05-28c#注册客户端事件示例
  • 2017-05-28DataGridView控件显示行号的正确代码及分析

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 深入理解C#序列化与反序列化的详解
    • C# WinForm应用程序降低系统内存占用方法总结
    • C#中out与ref的区别实例解析
    • C#生成PDF文件流
    • C#使用post发送和接收数据的方法
    • C#访问PostGreSQL数据库的方法
    • c++指针使用形参改变实参的方法
    • 算法练习之从String.indexOf的模拟实现开始
    • 浅谈C#中堆和栈的区别(附上图解)
    • 基于使用BeginInvoke,EndInvoke异步调用委托的实现代码

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有