当前位置:首页 > Windows程序 > 正文

[CLR via C#]委托

2021-03-26 Windows程序

委托是一种新的面向对象语言特性,委托的功能是在CLR的支持下实现的,这就意味着它并不受限于特定的编程语言,比如C#使用delegate关键字来定义委托,其他的.NET编程语言可以使用自己的方式来定义委托。

以委托作为基础,.NET构造了一个技术大厦,事件驱动、异步调用和Lambda表达式都建立于委托之上,还有许多其他的技术与委托有着密切的联系,掌握委托是探索这些技术领域的前提。

一、委托的简单使用

namespace ConsoleApplication1 { public delegate int MathOptDelegate(int x, int y); class Program { static void Main(string[] args) { MathOptDelegate mathOpt = Add; int z = mathOpt(3, 2); } private static int Add(int x, int y) { return x + y; } } }

从上例可以直观的感受到:委托可以看成是一个方法的"容器",将某一具体的方法"装入"后,就可以把它当成方法一样使用。但是不是所有的方法都可以赋值给mathOpt变量,必须满足一定的条件,定义委托类型时对方法的要求被称为方法的"签名"。

二、深入探索委托技术内幕

1.详解委托类型

用ILDASM打开编译后的项目文件,可以查看代码生成的IL指令。

不难发现使用delegate关键字定义一个委托类型时,其实是定义了一个新类MathOptDelegate,此类派生自MulticastDelegate,而MulticastDelegate又派生自Delegate。可以看到有一个构造函数和Invoke方法,继续查看Main方法,如下图所示:

查看IL_0007代码,发现调用了新生成的MathOptDelegate的构造函数,查看IL_0010代码,发现调用了MathOptDelegate的Invoke方法。所以通过委托变量间接调用方法,实际调用的是MathOptDelegate对象的Invoke方法。

通过查看IL代码,可以看到委托的真实面目,对于以下这条委托定义语句:

public delegate int MathOptDelegate(int x, int y);

C#编译器实际上是按照以下这个"代码模板"进行编译的:

public class MathOptDelegate : System.MultiDelegate { public MathOPtDelegate(Object target,Int32 methodPtr); public Int32 virtual Invoke (Int32 value1,Int32 value2); public virtual IAsyncResult BeginInvoke(Int32 value1,Int32 value2, AsyncCallback callback,Object object); public virtual Int32 EndInvoke(IAsyncResult result); }

注意MathOptDelegate类的构造函数,它接收两个参数target和methodPtr。

target:引用要调用方法的对象,如果调用的是静态方法,则target = null。

methodPtr:是一个方法指针,代表要调用的对象方法

2.委托调用列表

如果委托仅仅是方法调用的另一种方式,那何必多此一举引入"委托"这一特性?直接调用方法不更简单明了?对此问题的回答是:委托变量不仅可以引用一个方法,还可以组合多个方法并批量执行它们。

namespace ConsoleApplication1 { public delegate int MathOptDelegate(int x, int y); class Program { static void Main(string[] args) { MathOptDelegate a = Add; MathOptDelegate b = Divide; MathOptDelegate c = a + b; MathOptDelegate d = c - a; Console.ReadKey(); } private static int Add(int x, int y) { return x + y; } private static int Divide(int x, int y) { return x / y; } } }

Delegate定义了一个GetInvocationList静态方法用于获取委托调用列表(委托调用列表其实是委托对象内部所包容的一个数组,存放在数组中的元素是Delegate类型的实例,每个实例引用一个静态或实例方法),如果在代码中调用委托变量,将导致委托调用列表中的所有方法顺序执行,如果委托定义的方法有返回值,则多路委托变量的返回值为委托调用列表中最后一个方法的返回值。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/67939.html