19:定义并实现接口优于继承类型。
Prefer Defining and Implementing Interfaces to Inheritance。
接口支持多重继承,可以作用于值类型,而抽象类则不可以;抽象类中可以定义字段或方法,减轻创建子类(复用)的同时增加了子类与父类之间的耦合度;子类继承接口表达的是“can-do”的关系,而子类继承抽象类表达的是“is-a”的关系。
20:明辨接口实现和虚方法重写。
Distinguish Between Implementing Interfaces and Overriding Virtual Functions。
派生类不能重载基类(继承接口)中的接口成员。
21:使用委托表达回调
Express Callbacks with Delegates
返回值总是委托链上最后一个函数调用后返回的值;在委托链中抛出的任何异常都会终止委托链的继续调用。
22:使用事件定义对外接口。
Define Outgoing Interfaces with Events。
观察者模式(Observer Pattern).
23:避免返回内部类对象的引用。
Avoid Returning References to Internal Class Objects。
四个策略来保护类的内部数据结构不被无意的修改:值类型,恒定类型,接口和包装(模式)(e.g:返回DataView而不是DataSet)。
24:声明式编程优于命令式编程.
Prefer Declarative to Imperative Programming.
在C#中,编程时使用特性(Attribute)就是申明式编程。使用特性来表明意图时,可以减少在大量类似的手写算法中出现逻辑错误的可能。
25:尽可能将类型实现为可序列化的类型.
Prefer Serializable Types.
BinaryFormatter和SoapFormatter反序列化不会调用构造函数和属性访问器(property Set/Get)(如果有的话),且能够序列化非public成员;而XML反序列化会调用构造函数和属性访问器(如果有的话),且只能够序列化public属性和字段。
尽可能的使用默认序列化特性([SerializableAttribute]),当默认特性不满足时(e.g:在不同版本之间转换)要实现ISerializable 接口。
26:使用IComparable和IComparer接口实现排序关系。
Implement Ordering Relations with IComparable and IComparer.
IComparable是以提供方法来比较两个特定类型的对象;IComparer可以为排序提供一个可选的排序依据,这可以用于一些没有给你提供排序依据的类型上,提供你自己的排序依据。
e.g:http://support.microsoft.com/kb/320727/
27:避免ICloneable接口.
Avoid ICloneable.
对于值类型,不应该实现ICloneable接口,而应该使用赋值语句。对于引用类型,只有在确实必要进行拷贝时,才在子类上实现对ICloneable的支持;基类在可能要对ICloneable进行支持时,应该创建一个受保护的构造函数。总之,我们应该尽量避免使用ICloneable接口。
28:避免强制类型转换操作符。
Avoid Conversion Operators.
通过构造函数来代替定义类型转换操作。
29:只有当强制更新基类导致问题时才考虑使用new修饰符。
Use the new Modifier Only When Base Class Updates Mandate It.
在子类的方法上使用new修饰符,只是隐藏了从父类继承而来的方法,而并不是重写覆盖,因此在子类的方法表中,存在两个方法槽(slot)。当子类的引用调用该方法时,是调用子类中定义的方法;而当子类转化为父类的引用时,是调用父类中定义的方法!(关于这一点,也可以参考下我以前写的《Child类调用GrandFather类方法引发的思考》)。因此一般避免在方法上使用new修饰符。