Effective C# 重写优于事件处理器

许多.net类库中的类都提供了两种不同的处理事件句柄的方法。既可以为其添加事件,也可以重写其基类的事件抽象方法。为什么要为同一件事提供两种不同的方法呢?这是为了对应不同的情况。在实现派生类的时候,更好的选择是重写基类中的抽象方法。

      假设我们现在正在编写一个windows应用程序,这个程序需要对鼠标按键按下的事件做出响应。在自定义的Form类中,我们可以选择重写OnMouseDown()事件:

    public class MyForm : Form
    
{
        
protected override void OnMouseDown(MouseEventArgs e)
        
{
            
try
            
{
                HandleMouseDown(e);
            }

            
catch
            
{
                
//error
            }

            
base.OnMouseDown(e);
        }

    }

 

或者添加事件句柄:

 

    public class MyForm : Form
    
{
        
public MyForm()
        
{
            
this.MouseDown += new MouseEventHandler(MyForm_MouseDown);
        }


        
void MyForm_MouseDown(object sender, MouseEventArgs e)
        
{
            
try
            
{
                HandleMouseDown(e);
            }

            
catch
            
{
                
//error
            }

        }

    }

 

 

这里推荐使用第一种方法。一旦事件句柄抛出异常,不会再有其他的事件句柄被调用。这避免了一些错误代码继续被调用而引发的问题。通过重写受保护的虚方法,我们的句柄可以第一个被调用。基类中虚函数负责其他相关句柄的调用。这意味着如果需要调用那些事件句柄(一般来说是需要的),就要调用基类的虚函数。在有些特殊情况下我们需要替换基类的默认行为,可能不需要调用任何原有的事件句柄。虽然我们不能保证所有的事件句柄都被执行,因为其可能会抛出异常,但是我们可以保证派生类的行为是正确的。

      使用override比添加事件句柄高效的多。在 条款 22中展示了System.Windows.Forms.Control类是如何存储句柄时间并将其对应到每一个事件的。这种事件机制由于要检查事件句柄将造成更多的消耗。事件句柄列表中的每个方法都需要执行。相比重写虚方法,通过事件处理会消耗更多的时间。

      如果这还不足以说服你,咱们可以再回头看一下开始时候的代码。哪一种更清晰?重写虚方法只需要维护一个函数就可以达到检查和修改的目的。而事件机制需要两个维护点:事件句柄函数和事件绑定代码。其中任何一点都可能造成整体功能上的失败。一个函数显然要简单些。

      这些就是使用重写和不是事件句柄的理由。但是.net设计者之所以会提供事件也是有其理由的。他们不会做无用的工作。这种重写是针对派生类的。除此之外的情况我们必须使用事件机制。例如我们经常需要为Form添加一个按钮的点击事件。这个事件由按钮引发,在form中处理。当然我们可以搞一个自定义按钮,然后在里面重写点击的虚方法,但这太繁琐了,为了处理一个事件,需要创建一个自定义的按钮类,完全是在给自己找麻烦。而使用事件机制就非常的简单。这也是.net framework设计者在设计事件机制的一个理由。

      另外一个理由是事件的绑定是在运行期进行的。我们可以更加灵活的处理事件,在运行时为其绑定不同的事件。假设我们正在编写一个绘图程序,点击鼠标可能是画线的开始,也可能是选取某个对象。我们可以在使用者切换模式的时候来切换这些事件。而且,我们可以为同一个事件添加多个事件句柄。

      当我们创建派生类时,应当使用重写虚函数的方法来处理事件。这样便于维护也更加高效。其他情况则应该使用事件句柄。
posted @ 2008-11-06 13:31  瞪着你的小狗  阅读(668)  评论(0编辑  收藏  举报