委托及事件隐藏的信息

委托,是一种特殊的类,它是将调用时操作对象和指定方法的封装。委托的构造函数,需两个参数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个事件,也是通过这种方式实现用于减少内存的浪费。基本思想:让每个对象保存一个事件/委托对的集合,当新对象被构建时,集合为空;当事件被登记时,如果集合中存在,则将委托实例给合到委托链上;若不存在,则将新事件及实例添加到集合。

posted @ 2009-09-14 21:16  guzufeng  阅读(285)  评论(1编辑  收藏  举报