C#中委托的进一步理解

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

委托类型

其实,刚开始觉得委托类型是一个比较难理解的概念,怎么也不觉得下面的"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.通过委托实例调用委托

(0)

相关推荐

  • C#使用委托(delegate)实现在两个form之间传递数据的方法

    本文实例讲述了C#使用委托(delegate)实现在两个form之间传递数据的方法.分享给大家供大家参考.具体分析如下: 关于Delegate[代理.委托]是C#中一个非常重要的概念,向前可以推演到C++的指针,向后可以延续到匿名方法.lambda表达式. 现在我就从一个最简单最实用的一个小例子出发分析一下Delegate的使用. 现在有两个窗体Form1和Form2. 两个按钮Button1(Form)和Button2(Form2). Form1的代码: private void button

  • C#中委托的基本概念介绍

    最近在看深入理解C#,发现这是一本很不错的书,将很多C#的知识点联系了起来,更像是一本C#历史书,从C# 1一步步介绍到C# 4. 所以准备一边看,一边整理读书笔记.那么就先从委托开始. 委托是C#中一个非常重要的概念,从C# 1开始就有了委托这个核心概念,在C# 2和C# 3中委托又有了很多改进. 通过委托,我们可以将一个方法当作对象封装起来,并且在运行时,我们可以通过这个对象来完成方法的调用. 委托的使用 首先,来个简单的例子,苹果只负责设计iphone,而把组装iphone的工作委托给富士

  • 举例讲解C#编程中委托的实例化使用

    合并委托 本示例演示如何创建多播委托. 委托对象的一个有用属性是:可以使用 + 运算符将多个对象分配给一个委托实例.多播委托包含已分配委托的列表.在调用多播委托时,它会按顺序调用列表中的委托.只能合并相同类型的委托. - 运算符可用于从多播委托中移除组件委托. using System; // Define a custom delegate that has a string parameter and returns void. delegate void CustomDel(string

  • C#通过委托调用Button单击事件的方法

    这里介绍通过委托取消Button事件switch-case的方法.需要注意的是,事先要按顺序在各个Button的Tag属性中设置0.1.2.3--等序号,其作用请详看代码. /*定义委托*/ public delegate 类型或viod MethodDelegate(参数1, 参数2); private void buttonC_Click(object sender, EventArgs e) { Button button = (Button)sender; /*向委托添加方法*/ Met

  • C#异步委托调用实例分析

    本文实例讲述了C#异步委托调用实现方法.分享给大家供大家参考.具体如下: static void Main(string[] args) { //委托异步 Action<string> showMessage = ShowMessage; IAsyncResult result = showMessage.BeginInvoke("测试异步委托",null, null); //那在异步线程未完成工作以前主线程将处于阻塞状态 //等到异步线程结束,主线程才能继续工作 show

  • C#用匿名方法定义委托的实现方法

    本文实例讲述了C#用匿名方法定义委托的实现方法.分享给大家供大家参考.具体实现方法如下: //用匿名方法定义委托 class Program { delegate string MyDelagate(string val); static void Main(string[] args) { string str1 = " 匿名方法外部 "; //中括号部分定义来了一个方法,没有名称,编译器会定指定一个名称 MyDelagate my = delegate(string param)

  • C#中的委托、事件学习笔记

    1.委托delegate 委托delegate也是一种类型,在任何可以声明类的地方都可以声明委托,它将方法当做另一个方法的参数进行传递,这样就可以传递不同的方法,完成不同的功能,使程序具有很好的可扩展性. 举例: 假设这里有一台电脑,有人会用它写程序,有人会用它打游戏,有人会用它看电影,有人会用它边听音乐边玩游戏,有人会用它边听音乐边看文档,边上QQ. 这台电脑可以抽象成一个类Computer,里面有个方法DoWork,所有的人都要通过这个方法来做自己的事情. 不用委托的时候我们可以实现一些固定

  • C#中委托用法

    本文实例讲述了C#中委托用法.分享给大家供大家参考.具体分析如下: 对于用户要查找的条件的千变万化,我们在写条件去查找时,是不可能一下写死的,那样,如果你写好了一个类让别人用,别人需要的不是那种查询,得去找你改条件. 那么我们能否让使用这个类的人自己定义一个规则(条件),直接传条件给你,你帮我查询出结果来,C#就可以用委托来解决,相应的java可以用接口来实现 using System; using System.Collections.Generic; using System.Text; u

  • C#中的delegate委托类型基本学习教程

    委托 delegate 是表示对具有特定参数列表和返回类型的方法的引用的类型.在实例化委托时,你可以将其实例与任何具有兼容签名和返回类型的方法相关联.你可以通过委托实例调用方法. 委托用于将方法作为参数传递给其他方法.事件处理程序就是通过委托调用的方法.你可以创建一个自定义方法,当发生特定事件时,某个类(如 Windows 控件)就可以调用你的方法.下面的示例演示了一个委托声明: public delegate int PerformCalculation(int x, int y); 可将任何

  • C#中的委托介绍

    什么是委托? 之前写了事件的介绍:http://www.jb51.net/article/59461.htm 这里也把委托相关知识也总结一下. 委托是c#中类型安全的,可以订阅一个或多个具有相同签名方法的函数指针 声明委托的方式:delegate 返回值类型 委托类型名(参数) 比如: 复制代码 代码如下: delegate void StringProcess(string s); 注意:这里的除了前面的delegate,剩下部分和声明一个函数一样,但是StringProcess不是函数名,而

随机推荐