当前位置: 移动技术网 > IT编程>开发语言>c# > C#中委托的进一步理解

C#中委托的进一步理解

2019年07月18日  | 移动技术网IT编程  | 我要评论
文章介绍了委托的基本知识,接下来就进一步研究一下委托。 委托类型 其实,刚开始觉得委托类型是一个比较难理解的概念,怎么也不觉得下面的"assembleiphonehan

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

委托类型

其实,刚开始觉得委托类型是一个比较难理解的概念,怎么也不觉得下面的"assembleiphonehandler"是一个类型。

复制代码 代码如下:

public delegate void assembleiphonehandler();

按照正常的情况,如果我们要创建一个委托类型应该是:
复制代码 代码如下:

public class assembleiphonehandler : system.multicastdelegate
{
}

但是,这种写法是编译不过的,会提示不能从"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();
    }
}

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

1. 当下面三句执行完成后,可以通过vs看到d1、d2和d3的详细信息

复制代码 代码如下:

d1 = new apple.assembleiphonehandler(foxconn.assembleiphone);

复制代码 代码如下:

d2 = new apple.assembleiphonehandler(foxconn.packiphone);

复制代码 代码如下:

d3 = new apple.assembleiphonehandler(foxconn.shipiphone);

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

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

2. 通过"+="操作符来进行委托合并

复制代码 代码如下:

d4 += d1;

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

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

复制代码 代码如下:

d4 += d2;

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

4. 最后进行一次委托合并,把d3合并到d4中

复制代码 代码如下:

d4 += d3;

可以看到最新的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关键字声明委托类型

复制代码 代码如下:

[<修饰符>] delegate <返回类型> <委托名> ([<形参表>])

2.找到与委托签名相符的方法来创建委托实例,也可以通过"+="和"-="来组合和移除委托
复制代码 代码如下:

new <委托类型名> (<方法>)

3.通过委托实例调用委托

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

  • 如何使用C# 捕获进程输出

    intro很多时候我们可能会需要执行一段命令获取一个输出,遇到的比较典型的就是之前我们需要用 ffmpeg 实现视频的编码压缩水印等一系列操作,当时使用的是 f... [阅读全文]
  • 全面分析c# LINQ

    大家好,这是 [c#.net 拾遗补漏] 系列的第 08 篇文章,今天讲 c# 强大的 linq 查询。linq 是我最喜欢的 c# 语言特性之一。linq 是... [阅读全文]
  • C# DataTable常见用法汇总

    c# datatable 的常见用法:(1)新建数据表。(2)向表添加列。(3)设置表特定行与列的数据值。(4)将某行数据加入到表。(5)合并表。(6)复制表。... [阅读全文]
  • C# 如何解析获取Url参数值

    今天遇到一个需求,需要处理通过接口传过来的一个参数,参数内容为一个拼接好的url地址,且该地址还会携带了一些额外的参数,包括但不限于数字,字符串,json串。样... [阅读全文]
  • C# 实现dataGridView选中一行右键出现菜单的示例代码

    在窗体中添加datagridview控件和contextmenustrip1控件,修改datagridview属性,将contextmenustrip控件绑定d... [阅读全文]
  • WPF实现手风琴式轮播图切换效果

    WPF实现手风琴式轮播图切换效果

    本文实例为大家分享了wpf实现轮播图切换效果的具体代码,供大家参考,具体内容如下实现效果如下:步骤:1、自定义控件myimagecontrol实现图片的裁切和动... [阅读全文]
  • WPF实现3D翻牌式倒计时特效

    WPF实现3D翻牌式倒计时特效

    本文实例为大家分享了wpf实现3d翻牌式倒计时的具体代码,供大家参考,具体内容如下实现效果如下:思路:使用自定义控件,设置一个背板 mycardcontrolb... [阅读全文]
  • WPF实现平面三角形3D运动效果

    WPF实现平面三角形3D运动效果

    本文实例为大家分享了wpf实现平面三角形3d运动效果的具体代码,供大家参考,具体内容如下实现效果如下:思路:封装三角形三个顶点和路径的三角形类,图形渲染时同步更... [阅读全文]
  • WPF实现3D粒子波浪效果

    WPF实现3D粒子波浪效果

    本文实例为大家分享了wpf实现3d粒子波浪效果的具体代码,供大家参考,具体内容如下实现效果如下:步骤:1、3d粒子类particle.cs2、粒子系统parti... [阅读全文]
  • 谈谈c#中的索引器

    概念索引器(indexer) 允许类中的对象可以像数组那样方便、直观的被引用。当为类定义一个索引器时,该类的行为就会像一个 虚拟数组(virtual array... [阅读全文]
验证码:
移动技术网