9. 事件句柄声明不恰当
翻译概述:
微软在.NET中使用了一种新的数据类型——委托,通过委托实现了动态挂接和挂断程序执行逻辑,从而降低了模块之间的耦合度,提高了类型的可重用性。在.NET中,事件就使用了委托来实现。但是委托为我们提供了灵活性的同时,也为滥用提供了很大的便利性。因此,在本文中,微软建议了一个比较标准的事件声明格式,从而减低程序员或用户了解设计的难度。
在目前的程序设计语言中,各种新兴的技术为我们开发提供了很大的灵活度,例如:委托,反射、范型等等,甚至在学术界研究中的AOP(面向方面/侧面的编程)都会使我们的设计越来越容易和灵活,但是,同时,灵活性往往会带来很多对灵活性的滥用,例如比较有名的就是对范型的滥用。这些滥用会严重的降低程序的可维护性。因此,译者认为,我们必须有一整套的大家普遍接受的准则来保证我们代码的可维护性。这些准则可能会是很细节的,并且是非强制性的。开发人员都按照这样的准则进行开发,在部分的限制开发者的自由度的前提下,提高产品的可维护性。FxCop中间的大多数规则,译者认为都是这样的规则。例如这条规则就不能说它是好还是不好,但是如果所有开发者都遵照这样的约定,就会很大的减少开发人员与开发人员、开发人员与用户之间的沟通障碍。
原文引用:
Declare event handlers correctly
Rule Description Event handler methods take two parameters. The first is of type System.Object and is named 'sender'. This is the object that raised the event. The second parameter is of type System.EventArgs and is named 'e'. This is the data associated with the event. For example, if the event is raised whenever a file is opened, the event data typically contains the name of the file. Event handler methods should not return a value. In the C# programming language, this is indicated by the return type void. An event handler can invoke multiple methods in multiple objects. If the methods were allowed to return a value, there would be multiple return values for each event, and only the value of the last method invoked would be available. How to Fix Violations To fix a violation of this rule, correct the signature, return type, or parameter names of the delegate. For details, see the following example. When to Exclude Messages Do not exclude a message from this rule. Example Code The following example shows a delegate suitable for handling events. The methods that can be invoked by this event handler conform to the signature specified in the Design Guidelines. AlarmEventHandler is the delegate's type name. AlarmEventArgs derives from the base class for event data, EventArgs, and holds alarm event data. [Visual Basic]
Imports System
Namespace DesignLibrary Public Class AlarmEventArgs Inherits EventArgs Public Delegate Sub AlarmEventHandler(sender As Object, e As AlarmEventArgs) End Class End Namespace
[C#]
using System;
namespace DesignLibrary { public class AlarmEventArgs : EventArgs {} public delegate void AlarmEventHandler(object sender, AlarmEventArgs e); }
[C++]
#using <mscorlib.dll>
using namespace System; namespace DesignLibrary { public __gc class AlarmEventArgs : public EventArgs {}; __delegate void AlarmEventHandler( Object* sender, AlarmEventArgs* e); }
Related Rules See Also Event Usage Guidelines | Events and Delegates | System.EventArgs | System.Object |
引起的原因:
一个公共的或保护的事件句柄的委托类型的签名,返回类型或参数名称不恰当。
描述:
事件句柄方法一般有两个参数,第一个是System.Object类型的对象,一般命名为“sender”. 他表示谁发出了这个事件。另一个是System.EventArgs类型的对象,一般命名为“e”. 他包含这个事件相关的数据集。例如:如果一个打开文件产生一个事件,事件参数将包含文件名。
事件句柄方法应该不返回值(C#中返回类型为void)。一个事件句柄中可能调用多个对象中的不同方法,因此如果允许这些方法返回值,这里将会有多个返回值,但是我们只能获得最后一个被调用方法的返回值。
修复:
纠正委托的签名,返回值和参数名称。关于细节可以参考原文中的例子。
例程:
原文中的例子演示如何恰当的声明一个事件句柄所使用的委托类型。这个事件将要调用的方法会符合设计准则中的声明(signature这里不知道是否翻译正确)规范。委托的名字为“AlarmEventHandler”。事件参数类型名为“AlarmEventArgs”,该类型继承自EventArgs类型,该类型包含Alarm事件的数据。
例外:
无