.Net delegate类型:
委托跟回调函数是很有渊源的。回调其实跟通知机制有关,考虑这样一个基本的事件序列:a对象调用了b对象的某个方法,希望b对象在其方法完成之时调用a对象的某个方法。要实现这样的过程,要求b对象持有a对象的引用(引用一般作为b 对象方法的参数传入),且“知道”a对象的那个特定方法。这个方法就是我们说的那个回调函数。
本质上,.net的委托类型是一种类型安全的指向方法的对象(c++中如函数指针)亦或是指向一系列方法的对象。所谓类型安全指:类型必须匹配,变量或引用不能指向一个不是该类的对象,类型安全由编译器保障,违反类型安全编译时会给出提示。对函数指针而言,就是返回值,入口参数的数目,类型和顺序应一致。委托一般都是滞后调用,编写委托实现的人一般不知道具体何时该方法被调用。不象传统的C++方法指针,.net的委托是类且具有内建支持,可进行异步和广播式的调用。
委托跟事件event可自然的契合,一般是事件激发导致委托被调用。
委托对象含有三个重要的信息:1〉被调用方法的地址;2〉此方法的参数(如果有的话);3> 方法的返回值(如果有的话).不同于C++函数指针,.net委托既可指向实例方法也可指向静态方法.
一旦委托被创建且提供了足够的信息,便可在运行时调用它指向的方法.每个委托都可被异步和同步的调用,此点简化了编程工作:使得我们不用手工创建和管理线程对象,就可以在第二个线程中执行我们的方法.
C#中创建委托使用delegate关键字,委托名可以是任何你认为有意义的词.但必须使你的委托匹配你想指向的方法的签名.当C#的编译器处理委托类型时,会自动地生成一个密封(sealed)类,该类继承自System.MulticastDelegate.(这个类的父类是System.Delegate),此类提供了必要的基础结构便于委托持有一个方法的列表,这些方法会在后期的某个时间被调用
通过查看中间语言代码il(用ildasm.exe),可发现编译器会为委托类产生三个公共方法.Invoke();BeginInvoke()和EndIvoke();Invoke()是主要的方法,用于调用委托维护的每个方法.向所有同步调用一样,方法会阻塞调用者直到它执行完毕.Invoke方法也不必显式的调用,它工作于后台.后两个方法需配合使用用于异步执行委托指向的方法. 他们会在独立的线程中执行.
委托的构造方法: public TypeOfReturn MyDelegate(object target,uint fuctionAddress),可以看出它需要目标对象,和目标方法的函数地址.这个很易理解,所有方法的调用都遵循object.functionName(),的格式.不过还缺少:参数和返回 值.他们在上面提到的三个方法中给出: public TypeOfReturnValue Invoke([TypeOfParameter ParaX]*); //其中TypeOfReturnValue是返回值的类型,中括号里的是可不出现或可出现多个的参数列.异步方法对:public IAsyncResult BeginInvoke([TypeOfParameter ParaX]*);public TypeOfReturnValue EndInvoke(IAsyncResult result);可看出不同处:BeginInvoke先返回一个中间类型,在EndInvoke中才是目标返回值的类型; Invoke 方法给人这样的感觉: A--->C ; 而BeginIvoke和EndInvoke: A---->B B---->C 等价于A----C .
引入中间过程的原因是什么呢? 这个 问题以后在讨论吧:它跟异步执行有关,见后面的文章C#委托的异步使用。
下面是委托由编译器产生的伪码表示:
public sealed class DelegateName : System.MulticastDelegate
{
public DelegateName (object target, uint functionAddress);
public delegateReturnValue Invoke(allDelegateInputRefAndOutParams);
public IAsyncResult BeginInvoke(allDelegateInputRefAndOutParams,
AsyncCallback cb, object state);
public delegateReturnValue EndInvoke(allDelegateRefAndOutParams,
IAsyncResult result);
}
综述:C#委托,编译器会为其对应地产生一个密封(sealed)类,该类有三个核心方法,这些方法的参数和返回值基于委托的定义。
关键字delegate使得你自定义的委托是一个(“is-a”)MulticastDelegate.所有用该关键字修饰的定义类型都是MulticastDelegate的子类,而该类又是Delegate的子类:(public abstract class Delegate : ICloneable, ISerializable)
以下是我的简单学习测试:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelegateTest
{
public delegate string MyDelegateType(string firstArg,string secondArg);//创建了一个委托
public class SomeType {
public static string ClassMethodX(string str1,string str2){
System.Console.WriteLine("enter the static method <--");
try
{
System.Console.WriteLine("一些对参数的处理工作.......");
return String.Format("parameter1:{0} and Parameter2{1} come from a static Method", str1, str2);
}
finally {
System.Console.WriteLine("end the static method-->");
}
}
public string InstanceMethodX(string str1,string str2) {
System.Console.WriteLine("enter the instance method <--");
try
{
System.Console.WriteLine("一些对参数的处理工作.......");
return String.Format("parameter1:{0} and Parameter2{1} come from a instance Method", str1, str2);
}
finally
{
System.Console.WriteLine("end the instance method-->");
}
}
}
//程序入口:
class Program
{
static void Main(string[] args)
{
MyDelegateType myDelegate = new MyDelegateType(SomeType.ClassMethodX);//创建一个委托,帮定到一个静态方法上
System.Console.WriteLine("开始调用委托");
System.Console.WriteLine(myDelegate("参数一","参数二"));
System.Console.WriteLine("结束调用委托");
SomeType aUDTType = new SomeType();//实例化一个自定义的类实例(UDT--表示用户定义类型)
myDelegate += new MyDelegateType(aUDTType.InstanceMethodX);/*创建新的委托,帮定到一个实例类的方法中
委托的"+="操作等价于其Combine()方法,相应的"-="操作等价于Remove()方法,
此二者皆在父类(System.MultcastDelegate/System.Delegate)中定义
明白+=就是将新的委托成员加入委托列表中,-=为从其中挪去,另有removeALL()清空所有委托成员 */
System.Console.WriteLine("开始调用委托");
System.Console.WriteLine(myDelegate("参数一", "参数二"));
System.Console.WriteLine("结束调用委托");
System.Console.ReadLine();
}
}
}