Delegate (CLI)

委托(delegate)是一种类型安全的函数指针,用于通用语言运行库(CLI)。在C#中,delegate是一种class,包装了一个或多个函数指针及绑定的类实例。Delegate用来实现函数回调与事件接收(event listener)。Delegate对象可以作为参数传递给其他函数,以引用(referenced)封装在delegate对象中的函数,而无需在编译时刻就绑定被调用函数。 [1]

一旦为委托分配了函数方法,委托将与该函数方法具有完全相同的行为。 与委托的类型特征(由返回类型和参数组成)匹配的任何方法都可以分配给该委托。

C#例子

声明一个delegate类型,称作SendMessageDelegate, 以一个Message类型为参数,返回类型为void:

delegate void SendMessageDelegate(Message message);

下述代码定义了一个函数,以一个实例化的delegate类型作为形参:

void SendMessage(SendMessageDelegate sendMessageDelegateReference)
{
  // call the delegate and any other chained delegates synchronously
  sendMessageDelegateReference(new Message("hello this is a sample message"));
}

将要封装入delegate中的一个函数的定义:

void HandleSendMessage(Message message)
{
  // the implementation for the Sender and Message classes are not relevant to this example
  Sender.Send(message);
}

函数SendMessage,以SendMessageDelegate作为委托的实例作为实参:

SendMessage(new SendMessageDelegate(HandleSendMessage));

委托实例可以封装多个函数:

delegateType de1=fun1;
delegateType de2=fun2;
delegateType de3=de1+de2;//de3中有fun1、fun2两个函数的引用

技术实现细节

“委托”作为类,继承自System.MulticastDelegate(抽象类)。“委托”至少0个参数,至多32个参数,可以无返回值,也可以指定返回值类型。可以认为包含:一个类对象实例的地址(Target属性),该类的一个方法的地址(Method属性),以及另一个“委托”实例的引用(reference)。因此引用一个“委托”对象,可能实际上引用了多个“委托”的实例。“委托”对象被调用时,依次调用里面的多个“委托”的实例。这对于事件驱动的程序比较有用。

如果“委托”封装了一个静态函数,则其内部的绑定的类对象地址为null。

可以通过Delegate类的GetInvocationList()取出这些委托,并查看其Target和Method属性,获取所引用的方法名等资讯。

泛型委托

关键字Action定义了无返回值的泛型委托。Action从0个参数,至多16个参数。例如:

public Action<int> cwdelegate; //定义一个委托cwdelegate,参数是int,无返回值。

关键字Func定义了有返回值的泛型委托。从0个参数,至多16个参数。其中最右侧的泛型类型是返回值类型。

关键字Predict定义了返回值为bool的泛型委托。

在委托实例前,不加event,那这个委托就是一个普通的委托,可以在别的函数中调用,也可以直接用对象调用。但加上event关键字之后,只能用成员函数调用

用途

一个常用的用途是事件处理。CLI定义了控件的标准的事件处理函数是一个“委托”,声明如下:

 public delegate void EventHandler(object sender, EventArgs e)

这里第一个参数是发出该事件的控件的基类型object;后一个参数是事件数据的基类型EventArgs。以Button控件类为例,它有一个属性Click,定义为一个EventHandle类型的delegate:

 public event EventHandle Click;

至此,我们对一个具体的button实例变量,可以给它的Click事件追加上一个或多个事件处理函数:

 this.button1.Click += new System.EventHandler(this.button1_click);

对于Visual Basic,上述语句的写法是:

 AddHandler button1.click, AddressOf button1_Click

参考文献

  1. ^ Sturm, Oliver. Delegate calls vastly sped up in .NET 2. 2005-09-01 [2007-09-09]. (原始内容存档于2011-07-27). 

外部链接