委托及事件隐藏的信息

委托,是一种特殊的类,它是将调用时操作对象和指定方法的封装。委托的构造函数,需两个参数target,methodPtr分别用于指定操作的对象和方法。委托的调用通过Invoke方法,方法的原型及委托定义一致。委托同时提供了BeginInvoke及EndInvoke方法用于支持异步。

委托链的形成利用Delegate的基类MulticastDelegate的_prev字段,[关于Delegate与MultiCastDelegate],使用Combine和Remove方法操作委托链。

防止委托链中的由于单个委托出现异常或占阻塞,可利用MulticastDelegate的GetInvocationList()获取委托链中委托克隆体形成委托数组,用于实现对其的更多控制。

如果在不明确委托对应方法原型的时候使用委托。需要用到Delegate.CreateDelegate方法。

   public class Delegate

{

public static Delegate CreateDelegate(Type delType, System.Reflection.MemberInfo mi);

public static Delegate CreateDelegate(Type delType, Type type, string methodName);

public static Delegate CreateDelegate(Type delegateType, object obj, String methodName);

public static Delegate CreateDelegate(Type delegateType, object obj, string methodName, Boolean ignoreCase);

//......

public object DynamicInvoke(object[] args);

}

Demo:(通过指定生成委托对象的参数实现在未知方法原型时的调用)

namespace DelegateDemo

{

delegate object TwoInt32(int n1, int n2);

delegate object OneString(string s1);

class Program

{

static void Main(string[] args)

{

Delegate d = Delegate.CreateDelegate(typeof(TwoInt32), typeof(Program), "Add");

object result = d.DynamicInvoke(1, 2);

Console.WriteLine(result);

d = Delegate.CreateDelegate(typeof(OneString), typeof(Program), "NumChars");

result = d.DynamicInvoke("hello cnblogs!");

Console.WriteLine(result);

}

static object Add(int n1, int n2)

{

return n1 + n2;

}

static object NumChars(string s1)

{

return s1.Length;

}

}

事件的定义:
public event EventHandler MyEvent;

事件的作用是通知侦听事件的用户执行其自定义的操作。关于事件的侦听与注销,实则是对委托链的操作,编译器会将事件转化成一个委托字段及两个方法(add_*,remove_*用于操作委托字段)。 事件,我理解的是将有效信息包装到继承到EventArgs对象中,触发事件,通知事件侦听者作其定义的反应。事件的必须具备的三个能力:对象登记事件;对象注销事件;定义事件的对象维护登记对象的集合并通知。这三项功能从实现角度看,委托链都能做到,而事件是对委托链做了一层包装。博客园中有博友曾提过“事件与委托的关系好比字段与属性的关系。”这可以从显式控制事件注册的实现中看到:

显式控制事件注册:

public  delegate void SampleEventHandler(object sender,EventArgs args);

private SampleEventHandler sampleEventHandlerDelegate;

public  SampleEventHandler Sample

{

add

{

sampleEventHandlerDelegate = (SampleEventHandler)Delegate.Combine(sampleEventHandlerDelegate,value);

}

remove

{

sampleEventHandlerDelegate=(SampleEventHandler)Delegate.Remove(sampleEventHandlerDelegate,value);

}

}

从显式控制事件注册的代码可以很清晰的看出,是通过声明一个委托字段,然后定义其访问器来实现的。FCL中System.Windows.Forms.Control一个类中定义了近60个事件,也是通过这种方式实现用于减少内存的浪费。基本思想:让每个对象保存一个事件/委托对的集合,当新对象被构建时,集合为空;当事件被登记时,如果集合中存在,则将委托实例给合到委托链上;若不存在,则将新事件及实例添加到集合。

你可能感兴趣的:(事件)