首页 > 代码库 > 《.NET 设计规范》第 4 章:类型设计规范

《.NET 设计规范》第 4 章:类型设计规范

第 4 章:类型设计规范

4.1 类型和命名空间

  要用命名空间把类型组织成一个由相关的功能区所构成的层次结构中。

  避免非常深的命名空间层次。因为用户需要经常回找,所以这样的层次浏览起来很困难。

  避免有太多的命名空间。

  避免把为高级方案而设计的类型和为常见编程任务而设计的类型放在同一个命名空间中。

  不要不指定类型的命名空间就定义类型。

  要把那些为基本命名空间提供设计时功能的类型放在带“.Design”后缀的命名空间中。

  要把那些为基本命名空间提供自定义权限的类型放在带“.Permissions”后缀的命名空间中。

  要把那些为基本命名空间提供互操作功能的类型放在带“.Interop”后缀的命名空间中。

  要把所有位于主互操作程序集中的代码放在带“.Interop”后缀的命名空间中。

 

4.2 类和结构之间的选择

  考虑定义结构而不要定义类 - 如果该类型的实例比较小而且声明周期比较短,或者是经常被内嵌在其它对象中。

  避免定义结构,除非该类型具有以下所有特征。

    它在逻辑上代表一个独立的值,与基本类型(int、double 等等)相似;

    它的实例的大小小于 16 个字节;

    它是不可变的;

    它不需要经常被装箱。

  

4.3 类和接口之间的选择

  要优先定义类而不是接口

  要用抽象类而不是用接口来解除契约与实现之间的耦合。

  要定义接口 - 如果需要提供多态层次结构的值类型的话。

  考虑通过定义接口来达到与多重继承相类似的效果。

  

4.4 抽象类的设计

  不要在抽象类型中定义公有的或内部受保护的构造函数。

  要为抽象类定义受保护的构造函数或内部构造函数。

  要为每个抽象类提供至少一个继承自该抽象类的具体类型。

  

4.5 静态类的设计

  要尽量少用静态类。

  不要把静态类当做是杂物箱。

  不要声明或覆盖静态类中的实例成员。

  要把静态类定义为密封的、抽象的,并添加一个私有的实例构造函数 - 如果编程语言不直接支持静态类。

  

4.6 接口的设计

  要定义接口 - 如果想让一组包括值类型在内的类型支持一些公共的 API。

  考虑定义接口 - 如果想让已经继承自其它基类的类型支持该接口提供的功能。

  避免使用记号接口(没有成员的接口)。

  要为接口提供至少一个实现该接口的类型。

  要为每个接口提供至少一个使用该接口的 API(一个以该接口为参数的方法,或是一个类型为该接口的属性)。

  不要给已经发行的接口再添加成员。

 

4.7 结构的设计

  不要为结构提供默认的构造函数。

  不要定义可变的值类型。

  要确保当结构实例的所有数据都为 0、false 或 null(如果合适)时,结构仍处于有效状态。

  要为值类型实现 IEquatable<T>。

  不要显式地扩展 System.ValueType,事实上大多数编程语言不允许这样做。

 

4.8 枚举的设计

  要用枚举来加强那些表示值的集合的参数、属性以及返回值的类型性。

  要优先使用枚举而不要使用静态常量。

  不要把枚举用于开放的集合(比如操作系统的版本、朋友的名字等)。

  不要提供为了今后使用而保留的枚举值。

  避免显示地暴露只有一个值的枚举。

  不要在枚举中包含 sentinel 值。

  要为简单枚举类型提供零值。

  考虑以 Int32 为载体来实现枚举(大多数编程语言的默认选择),除非下面的任何一条成立。

  要用复数名词或名词短语来命名标记枚举,用单数名词或名词短语来命名简单枚举。

  不要直接扩充 System.Enum。

  要对标记枚举使用 System.FlagsAttribute。不要把该修饰属性用于简单枚举。

  要用 2 的幂次方作为标记枚举的值,这样就可以使用按位 OR 操作来自由地组合他们。

  考虑为常用的标记组合提供特殊的枚举值。

  避免让创建的标记枚举包含某些无效的组合。

  避免把 0 用作标记枚举的值,除非该值表示“所有标记都被清除”,而且按下一条规范进行了适当地命名。

  要把标记枚举的 0 值命名为 None。对标记枚举来说,该值必须始终表示“所有标记均被清除”。

  考虑给枚举添加值,尽管要冒一点兼容性的风险。

  

4.9 嵌套类型

  要在想让一个类型能够访问外层类型的成员时才使用嵌套类型。

  不要用公共嵌套类型来进行逻辑分组,应该用命名空间来达到这一目的。

  避免公开地暴露嵌套类型。除非是只需在极少数的情况下声明嵌套类型的变量,比如派生子类时,或者其它需要定制的高级场景中。

  不要使用嵌套类型 - 如果该类型可能会被除了它的外层类型之外的类型引用。

  不要使用嵌套 - 如果需要让客户代码来实例化它们。如果某个类型具有公有构造函数,那么他不应该被嵌套在其它类型中。

  不要把嵌套类型定义为接口的成员,许多编程语言不支持这样做。

 

4.10 类型和程序集元数据

  要在包含公共类型的程序集中使用 CLSCompliant(true) 修饰属性。

  要在包含公共类型的程序集中使用 AssemblyVersionAttribute 修饰属性。

  考虑在程序集版本号中使用 <V>、<S>、<B>、<R> 的格式。其中 V 是主版本号,S 是服务版本号,B 是构建号,R 是构建修订号。

  要在程序集中使用下面的修饰属性来提供额外的信息。

  考虑在程序集中使用 ComVisible(false)。可供 COM 调用的 API 需要特别地设计。

  考虑在程序集这种使用 AssemblyFileVersionAttribute 和 AssemblyCopyrightAttribut,其目的是为了提供与程序集有关的额外信息。

 

《.NET 设计规范》第 4 章:类型设计规范