初识委托
委托是一种定义方法签名的类型。实例化委托时,可以将其实例与任何具有兼容签名的方法相关联。通过委托实例调用方法。委托用于将方法作为参数传递给其他方法。事件处理就是通过委托调用的方法
声明一个委托
//声明一个委托类型
//方法获取2个Int32类型的参数 ,返回值为void
public delegate void PerformCalculation(int num1, int num2);
使用委托
直接上代码:
//声明委托 internal delegate void PerformCalculation(int num1, int num2); static void Main(string[] args) { //创建委托对象 new运算符实例化委托 PerformCalculation myDelegate = new PerformCalculation(Add); //调用委托 myDelegate(100, 100); Program p = new Program(); CallBack(1000, 10, p.Division); //快捷语法实例化委托 PerformCalculation myDelegate1 = Minus; myDelegate1(200, 10); ChainDelegateDemo1(p); ChainDelegateDemo2(p); Console.ReadKey(); } public static void ChainDelegateDemo1(Program p) { Console.WriteLine("****** chain delegate demo ******"); PerformCalculation pc1=new PerformCalculation (Add); PerformCalculation pc2 = new PerformCalculation(Minus); PerformCalculation pc3 = new PerformCalculation(p.Division); PerformCalculation pc4 = new PerformCalculation(Multiply); PerformCalculation pcChain = null; pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc1); pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc2); pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc3); pcChain = (PerformCalculation)Delegate.Combine(pcChain, pc4); pcChain(100, 50); } public static void ChainDelegateDemo2(Program p) { Console.WriteLine("****** chain delegate demo2 ******"); PerformCalculation pc1 = new PerformCalculation(Add); PerformCalculation pc2 = new PerformCalculation(Minus); PerformCalculation pc3 = new PerformCalculation(p.Division); PerformCalculation pc4 = new PerformCalculation(Multiply); PerformCalculation pcChain = null; pcChain += pc1; pcChain += pc2; pcChain += pc3; pcChain += pc4; pcChain(200, 100); } public static void CallBack(int num1, int num2, PerformCalculation cal) { if (cal!=null) { cal(num1, num2); } } public static void Add(int num1, int num2) { Console.WriteLine(num1 + num2); } public static void Multiply(int num1, int num2) { Console.WriteLine(num1 * num2); } public static void Minus(int num1, int num2) { Console.WriteLine(num1 - num2); } public void Division(int num1, int num2) { Console.WriteLine(num1 / num2); }
Program 类定义了静态方法CallBack。CallBack方法获取2个Int32类型的整数,一个PerformCalculation委托对象的引用。CallBack内部地用 cal变量指定的回调方法。Program 类中Add、Multiply、Minus为静态方法,Division为实例方法。
总结:
- 委托声明使用关键字delegate,与方法相似又返回值和签名,但是没有方法体
- 实例化委托对象时可以使用new运算符,也可以是用快捷语法
委托揭秘
编译器生成的代码:
1、声明的委托PerformCalculation被编译成同名的类,包含一个构造器,3个方法(BeginInvoke、EndInvoke、Invoke),完整的PerformCalculation类
internal class PerformCalculation : System.MulticastDelegate { public PerformCalculation(object obj, IntPtr method); public virtual void Invoke(Int32 num1, Int32 num2); public virtual IAsyncResult BeginInvoke(Int32 num1,Int32 num2,AsyncCallback callback,Object obj); public virtual void EndInvoke(IAsyncResult result); }
2、所有的委托都派生自System.MulticastDelegate类,System.MulticastDelegate派生自System.Delegate类。
System.MulticastDelegate类的3个重要的非公共字段
字段 |
类型 |
说明 |
_target | System.Object |
当委托对象包装一个静态方法时,这个字段为null。当委托对象包装一个实例方法时,这个字段引用的回调方法要操作的对象。 换言之,这个字段指出要传给实例方法的隐式参数this的值 |
_methodPtr | System.IntPtr | 一个内部的整数值,CLR用它标识要回调的方法 |
_invocationList | System.Object | 该字段通常为null。构造一个委托链时,它可以引用一个委托数组 |
Delegate类中定义了两个只读的公共实例属性,分别是Target和Method,Target属性返回保存在私有字段_target中的值。如果委托对象包装的是一个静态方法,Target将返回null。Method属性返回对一个System.Reflection.MethodInfo对象的引用,该对象标识了回调方法。实际例子:
//创建委托对象 new运算符实例化委托 PerformCalculation myDelegate = new PerformCalculation(Add); //调用委托 myDelegate(100, 100); Console.WriteLine("Target:{0} Method:{1}",myDelegate .Target,myDelegate.Method); Program p = new Program(); myDelegate=p.Division; myDelegate(100, 100); Console.WriteLine("Target:{0} Method:{1}",myDelegate .Target,myDelegate.Method);
调用结果:
委托链
委托链是由委托对象构成的一个集合。利用委托链,可以调用集合中的委托所包装的全部方法。
委托链示例见demo,ChainDelegateDemo1、ChainDelegateDemo2 方法。
- 构造委托链会使用System.Delegate 的Combine静态方法,移除委托使用System.Delegate 的Remove静态方法。C#编译器自动为委托类型的实例重载了+= 和-=操作符。操作符分别调用System.Delegate.Combine和System.Delegate.Remove
- 当构造委托链时,_invocationList字段会被初始化为引用一个委托对象的数组,这一点也非常重要
园中的优秀文章