代码改变世界

Effective C# 学习笔记(三十)多用重载少用事件处理器

2011-07-17 21:12  小郝(Kaibo Hao)  阅读(400)  评论(0编辑  收藏  举报

.net中有两种实现事件机制的方式,一种方式是附加一个事件处理器,另一种是重载基类的虚方法。此两种方式各有其适用的环境。

 

重载基类虚方法的好处在于你可以控制你子类的实现事件行为。因为事件是累加的,从子类重载到父类重载,由下至上,子类的实现先被调用,然后是父类的,这样你至少可以保障你子类的行为是可控的,异常是可捕捉可处理的。然后你还可以控制是否在子类的重载中调用父类的实现,这样的自由度和可控性是事件处理器机制不可比拟的。而且在性能方面重载基类虚方法也更胜一筹,因为调用一个虚方法要比检查一个事件处理器是否由附加处理方法,而且在运行时必须迭代所有的调用列表以执行注册的方法要快得多。

 

再有对于维护上,重载基类虚方法只需维护该虚方法的子类重载即可,而对于事件处理器来说则需要维护事件注册地方和事件注册的方法实现两个地方。

 

当然对于事件处理器来说也不是没有用武之地,重载父类虚方法适用于可被继承的类。其他情况你就适用事件处理器吧。

 

用于设计与实现的分工

比如WPF中,使用XAML语言描述事件注册,而在C#代码中来实现事件的逻辑。这样设计人员只需关心如何设计事件的调用行为流程,然后在XAML中声明这些事件注册。开发人员最终来实现这些事件的处理方法。

 

用于在运行时获得事件绑定的动态灵活性

由于事件机制是在运行时动态解析执行的,所以你可以根据运行的环境来配置管理事件的执行方法。比如实现一个画图程序,鼠标的点击事件有可能是画一个点,也有可能是选择一个图片元素,这就要根据当前鼠标的状态来判断该事件到底应该绑定哪个事件了。

 

对于一个事件相关的多个方法可分别定义维护

对于一个事件处理器可以hook up多个事件处理方法。如画图程序中,某个事件可能先触发执行某个操作,再更新状态栏,然后再控制其他命令的可执行状态。

 

下面以代码为例说明两种方法的实现不同,这里以WPF应用程序的一个OnMouseDown事件为例:

 

//重载OnMouseDown方法

public partial class Window1 : Window

{

// other code elided

public Window1()

{

InitializeComponent();

}

protected override void OnMouseDown(MouseButtonEventArgs e)

{

DoMouseThings(e); //执行子类的逻辑

base.OnMouseDown(e);//执行父类的逻辑

}

}

 

//使用事件处理器机制

//1. XAML中声明事件

<!-- XAML File -->

<Window x:Class="Item36_OverridesAndEvent.Window1"

xmlns=

"http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Title="Window1" Height="300" Width="300"

MouseDown="OnMouseDown">

<Grid>

</Grid>

</Window>

 

//2. 在代码中实现事件相关的方法

// C Sharp file:

public partial class Window1 : Window

{

// other code elided

public Window1()

{

InitializeComponent();

}

private void OnMouseDown(object sender,MouseButtonEventArgs e)

{

DoMouseThings(e);

}

private void DoMouseThings(MouseButtonEventArgs e)

{

throw new NotImplementedException();

}

}