最近想把Winform的事件处理机制理一理,,看来看去,发现所有的控件都基于System.Windows.Forms.Control,所以选取其中的一个Click事件进行研究。希望能够搞清楚事件的底层原理。
1,首先来看下Control类的定义 public class Control : Component,...接口略....,{...内容略.....}
Control类本身继承自Componet,暂时只关注Componet里边放了一些Control类会用到的一些东西,
比如其中的:protected EventHandlerList Events; 这个是用来存放事件处理器的,类似于数组,依靠一个key来定位不同的事件的处理器。主要关注其中的AddHandler()和RemoveHandler(),当我们使用+=,-=操作符添加/删除事件订阅时,实际上就是调用了这两个方法。看下Control里边的Click事件的来龙去脉:
先是一个事件的属性(不知道是不是这么叫?),普通的属性里边是get,set,而这个方法属性里边是add,remove,对应着+=和-=,如上边所说,最终是调用AddHandler()和RemoveHandler(),第一个参数是一个key,用于后续rise对应的事件,value就是咱们+=或-=操作符后边的那个方法。
public event EventHandler Click {
add { base.Events.AddHandler(EventClick, value); }
remove { base.Events.RemoveHandler(EventClick, value); }
}
2,事件有了,现在看看触发它的方法:
protected virtual void OnClick(EventArgs e) {
((EventHandler)base.Events[EventClick])?.Invoke(this, e);
}
可以看到, 触发方法里边,跟我们自己定义事件还是有很大区别的。我们自己定义的,通常都是 直接拿事件名字来Invoke,比如Click事件就直接Click.Invoke(),而这里是把所有事件处理器全部存在Events里边。触发时先通过对应的key找到,强制转换为对应类型的事件处理器,然后再来Invoke它。
3,接下来看看谁来触发它:
这里代码较多,用图片表示一下,最终这个Click事件由WmMouseUp,也就是鼠标抬起时调用,从而触发,可以看到OnClick和OnMouseClick是一起执行的。此处OnClick()的第一个参数应该是EventArgs,但是此处给的是MouseEventArgs,也行,因为
MouseEventArgs是EventArgs的子类,可以理解为:儿子代表父亲没问题,因为子类继承了父类的一切,需要的他都有所以可以代表
先扒到这里,回头再研究一下EventHandlerList这个东西, 希望有大佬指点一二。
最后附上作为方法的参数子类可以代表父类的官方解释:
在 C# 中,当方法的参数类型是父类时,我们可以将子类的实例作为参数传递给该方法。这被称为多态性,是面向对象编程的一个重要特性。在这种情况下,方法会根据传入的参数类型自动进行类型转换,并执行相应的操作。