从代码层面上来说是,事件触发了回调,在CLR中委托是目前实现回调的首选的方法,把委托理解成一个指向函数的指针是有帮助的。这个函数可以是静态的也可以实例的,委托实际上和thunk一样的,唯 一不同的在cLR中是首选的,当你在代码中声明一个委托时,C#编辑器会从MulticastDelegate中派生一个类,并且在运行时,CLR动态实现委托所有有趣的方法,因此用ILDASM查看编译后的结果是看不到委托方法身后的中间代码的。
委托包含一对有用的字段,第一个字段是该对像的引用,第二个是存放一个方法的指针,实现是首先通过包含对像引用调用,然而对像的引用是null运行时明白这意味着该方法是一个静态方法,一个委托类型可以处理对实例方法或静态方法的回调,而且调用一个委托,从语法上来看和调用一个常规的函数是一样的,因此委托更适合实现回调。
委托的声明:
public delegate double ProcessResult(double x,double y);
当C#编译器遇到这一行代码是会定义一个从MulticastDelegate中派生的类型,该类型也实现一个名为Invoke的方法,此方法的签名和在委托声明中所描述的方法一模一样的,实际上,该派生的类如下所示
public class ProcessResult : System.MulticastDelegate
{
public double Invoke (double x,double y);
}
编译器抽象了委托的使用,使语法简化,通常你会用类似的方法而不是用Invoke方法来调用委托。
当使用一个委托实例时,必须写一个方法,当委托调用的时候会调用这个方法,方法可以静态实例都可以,它的签名与委托名相兼容,因此参数的类型和返回值类型必须和委托声明相一致,或者可以隐式的转变成委托声明的类型。
个人感觉声明一个委托就是标志一个要回调用的函数的参数还有返回值,只是要调用函数的参数的种类及个数,与委托的初始化的参数无关,可以是一个对象的方法,但是方法却与委托声明的一致也是可以的。
对于静态的方法,可以直接使用类名来调用,而且调用委托也不用给参数,可以简化,静态的方法用来表示,可以是一个方法组,当然也可以用实例的方法来调用 。可以多个委托连接在一起,可以发生多次动作,
委托链
就是创建一个委托的链表,当链表头的委托被调用的时候,整个链表的所有的委托都会被调用,System.Delegate类提供了一些静态方法去管理委托链表,
public class Delegate:ICloneable,Iserializable
{
public static Delegate Combine(Delegate[]);
public static Delegate Combine(Delegate first,Delegate Second);
}
不论是一组委托还是一对都可以构成一个委托链,每个Delegate实例自己就可以是一个委托链因此可以见到复杂的委托嵌套。
从委托链里移除委托,最终要依赖System.Delegate中的两个的静态的方法
public class Delegate :IClonable,ISerializable
{
public static Delegate Remove (Delegate source ,Delegate value);
public static Delegate RemoveAll (Delagete source,Delegate value);
}
Remove移除的是最后一个委托,而RemoveAll刚是移除所有的符合条件的委托
C#重载了这些操作可以用—和+号来进行操作
对于一组的委托可以通过GetInvocationList方法获取一组委托,然后可以按自己想要的顺序调用它们。
到现在,所有的委托都是提供了一个具体实例的方法,在调用一个实例方法的时候,参数隐藏了一个this它代表了当前的实例,
应当使用最一般的,有一个泛型来公开一个实例的委托。
事件
就是编译器内部会实现一些隐藏的方法去允许注册委托和解除委托,这个委托在一个特定事件发生的时候调用。本质上来说,一个事件就是一个快捷方式,它节省了写注册委托和解除注册委托的方法和时间,而那些方法在管理委托链的时候必须要写的,