深入理解C#委托及原理

来源:互联网 发布:睿知而行 编辑:程序博客网 时间:2024/05/21 10:17

深入理解C#委托及原理

 ----------------------广州java培训机构广州.Net培训机构java培训机构----------------------期待与您交流

 

一、委托

设想,如果我们写了一个厨师做菜方法用来做菜,里面有 拿菜、切菜、配菜、炒菜 四个环节,但编写此方法代码的人想让 配菜 这个环节让调用方法的人实现,换句话说,就是想在方法被调用时接收 代码 作为参数,在方法中执行这端传进来的代码。

但,怎么为一个方法传 代码 进来呢?当然大家想到了传递接口方式来实现,咱先不讨论接口,因为微软为我们提供了一个叫做 【委托】 的类型。广州java培训广州.Net培训

 

(一)、委托基础:

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++ 中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后调用该委托对象就可以执行委托对象内方法引用指向的方法,而不必在编译时知道将调用哪个方法(如参数为委托类型的方法,也就是提供了为程序回调指定方法的机制)。”-- 引自MSDN

 

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

 

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

 

(4)概要图例:

DGSayHi dgObj new DGSayHi(SayHi);

dgObj(“James”); //调用委托对象,就会执行委托对象里的方法。

深入理解C#委托及原理


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)概要图例

深入理解C#委托及原理




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.开始-程序-如图:
深入理解C#委托及原理



b.打开项目文件夹下的binDebug文件夹,找到程序集 CodeForFun.exe,拖入到【IL反汇编程序】界面中便可看到程序集的IL代码:

找到我们定义了委托DGSayHi的类DelegateForFun,发现,里面的 委托类型声明 代码

编译前:delegate string DGSayHi(string uName);

变成了一个类:


深入理解C#委托及原理

单击展开后我们再来看看:

深入理解C#委托及原理


看出什么了?

(I).继承了System.MulticastDelegate

(II).包含了构造方法、BeginInvokeEndInvokeInvoke方法。

也就是说此时,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  

深入理解C#委托及原理




a.三者的作用:

_methodPtr 里保存的就是 方法指针。

_target 里用来保存方法所在的对象。

_invocationList 其实使用时是个object数组,在注册多个方法时,其他方法就保存在此成员中,而它也就是 委托链 的关键容器。

 

b.概要图:

深入理解C#委托及原理


图中的委托对象 dgObj 在创建时创建了指向方法 SayHi的指针并保存在 _methodPtr中;_target中保存了SayHi方法所在的类的对象(比如我把这段代码写在窗体里按钮的点击方法中,那么此时 _target就是 SayHi方法所在的窗体对象)_invocationList 中保存了追加的两个方法的指针,但这两个方法指针都是分别被装在 MuticastDelegate对象中。

----------------------广州java培训广州.Net培训java培训----------------------

期待与您交流!


原创粉丝点击