Page 29
其余情况下,您应该定义类,而不是结构体。
3.9 类
?一定请使用继承来表示 “is a” 关系,例如 “猫是一种动物”。
?一定请使用接口,例如IDisposable,来表示 “can do” 关系,例如 “对象能被释放”。 3.9.1 字段
?一定不要提供Public或Protected的实例字段。Public或Protected字段并没有受到代码访问安全需求的保护。我们应该使用Private字段,并通过属性来提供访问接口。
?一定请将预定义对象实例定义为public static readonly字段。
?一定请将永远不会改变的字段定义为常量字段。
?一定不要将可变类型定义为只读字段。 3.9.2 属性
?一定请创建只读属性,如果用户不应该具有修改这些属性值的能力。
?一定不要提供只写属性。如果没有提供属性设置器,请使用一个方法来实现相同的功能。方法名应该以Set开头,后面跟着属性名。
?一定请为所有属性提供合理的默认值,并确保默认值不会引发安全漏洞或一个极端低效的设计。
?您不应该从属性访问器内抛出异常。属性访问器应该只包含简单的操作,且不带任何前置条件。如果一个属性访问器可能抛出异常,那么考虑将其重新设计为一个方法。该推荐方法并不适用于索引器。索引器可以因为无效实参而抛出异常。从属性设置器内抛出异常是有效且可接受的。
? 2016 Microsoft Corporation. All rights reserved.
Page 30
3.9.3 构造函数
?一定请尽量减少构造函数的工作量。除了得到构造函数参数,设置主要数据成员,构造函数不应该有太多的工作量。其余工作量应该被推迟,直到必须。
?一定请在恰当的时候,从实例构造函数内抛出异常。
?一定请在需要默认构造函数的情况下,显式的声明它。即使有时编译器为自动的为您的类增加一个默认构造函数,但是显式的声明使得代码更易维护。这样即使您增加了一个带有参数的构造函数,也能确保默认构造函数仍然会被定义。
?一定不要在对象构造函数内部调用虚方法。调用虚方法时,实际调用了继承体系最底层的覆盖(override)方法,而不考虑定义了该方法的类的构造函数是否已被调用。
3.9.4 方法
?一定请将所有输出参数放置于所有传值和传引用参数(除去参数数组)的之后,即使它引起了重载方法之前不一致的参数顺序。
?一定请验证传递给Public,Protected或显式实现的成员方法的实参。如果验证失败,则抛出
System.ArgumentException,或者其子集:如果一个 null 实参传递给成员,而成员方法不支持null实参,则抛出ArgumentNullException。如果实参值超出由调用方法定义的可接受范围,则抛出ArgumentOutOfRangeException异常。 3.9.5 事件
?一定请注意事件处理方法中可能会执行任意代码。考虑将引发事件的代码放入一个try-catch 块中,以避免由事件处理方法中抛出的未处理异常引起的程序终止。
? 2016 Microsoft Corporation. All rights reserved.
Page 31
?一定不要在有性能要求的API中使用事件。虽然事件易于理解和使用,但是就性能和内存消耗而言,它们不如虚函数。
3.9.6 成员方法重载
?一定请使用成员方法重载,而不是定义带有默认参数的成员方法。默认参数并不是CLS兼容的,所以不能被某些语言重用。同时,带有默认参数的成员方法存在一个版本问题。我们考虑成员方法的版本1将可选参数默认设置为123。当编译代码调用该方法,且没有指定可选参数时,编译器在调用处直接将123嵌入代码中。现在,版本2将默认参数修改为863,如调用代码没有重新编译,那么它会调用版本2的方法,并传递123作为其参数。(123是版本1的默认参数,而不是版本2的。)。
Good:
PublicOverloadsSub Rotate(ByVal data As Matrix) Rotate(data, 180) EndSub
PublicOverloadsSub Rotate(ByVal data As Matrix, ByVal degrees AsInteger) ' Do rotation here EndSub
Bad:
PublicSub Rotate(ByVal data As Matrix, OptionalByVal degrees AsInteger = 180) ' Do rotation here EndSub
?一定不要任意改动重载方法中的参数名。如果一个重载函数中的参数代表着另一个重载函数中相同的参数,该参数则应该有相同的命名。具有相同命名的参数应该在重载函数中出现在同一位置。
?一定请仅将最长重载函数设为虚函数(为了拓展性考虑)。短重载函数应该一直调用到长重载函数。 3.9.7 接口成员
?您不应该在没有合理理由的情况下显式的实现接口成员。显式实现的成员可能使开发者感到困惑,因为他们不会出现在Public成员列表内,且会造成对值类型不必要的装箱拆箱操作。
? 2016 Microsoft Corporation. All rights reserved.
Page 32
?您应该在成员只通过接口来调用的情况下,显式的实现成员接口。 3.9.8 虚成员方法
相较于回调和事件,虚成员方法性能上有更好的表现。但是比非虚方法在性能上低一点。
?一定不要在没有合理理由的情况下,将成员方法设置为虚方法,您必须意识到相关设计,测试,维护虚方法带来的成本。
?您应该倾向于为虚成员方法设置为Protected的访问性,而不是Public访问性。Public成员应该通过调用Protected的虚方法来提供拓展性(如果需要的话)。
3.9.9 静态类
?一定请合理使用静态类。静态类应该被用于框架内基于对象的核心支持辅助类。 3.9.10 抽象类
?一定不要在抽象类中定义Public或Protected-Internal的构造函数。
?一定请为抽象类定义一个Protected,或Internal构造函数。
Protected构造函数更常见,因为其允许当子类创建时,基类可以完成自己的初始化工作。
publicabstractclassClaim {
protected Claim() {
... } }
internal 构造函数用于限制将抽象类的实现具化到定义该类的程序集。
publicabstractclassClaim
? 2016 Microsoft Corporation. All rights reserved.