《.NET 设计规范》第 8 章:使用规范_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > 《.NET 设计规范》第 8 章:使用规范

《.NET 设计规范》第 8 章:使用规范

 2017/8/21 21:09:19  骨折仔(原名反骨仔)  程序员俱乐部  我要评论(0)
  • 摘要:第8章:使用规范8.1数组要在公共API中优先使用集合,避免使用数组。不要使用只读的数组字段。虽然字段本身是只读的,用户不能修改它们,但用户可以修改数组中的元素。考虑使用不规则数组,而不要使用多维数组。8.2修饰属性要在命名自定义修饰属性类时添加“Attribute”后缀。要在定义自己的修饰属性时使用AttributeUsageAttribute。要将必填参数定义为只读属性。要提供构造函数参数来对必填参数进行初始化。每个参数的名字应该与对应属性的名字相同(但大小写会不同
  • 标签:.net 使用 net 设计

第 8 章:使用规范

8.1 数组

  要在公共 API 中优先使用集合,避免使用数组。

  不要使用只读的数组字段。虽然字段本身是只读的,用户不能修改它们,但用户可以修改数组中的元素。

  考虑使用不规则数组,而不要使用多维数组。

  

8.2 修饰属性

  要在命名自定义修饰属性类时添加“Attribute”后缀。

  要在定义自己的修饰属性时使用 AttributeUsageAttribute。

  要将必填参数定义为只读属性。

  要提供构造函数参数来对必填参数进行初始化。每个参数的名字应该与对应属性的名字相同(但大小写会不同)。

  避免提供构造函数参数来对可选属性(可选参数)进行初始化。

  避免对自定义修饰属性的构造函数进行重载

  要尽可能将自定义修饰属性类密封起来。这样会使对修饰属性的查找更快。

  

8.3 集合

  不要在公共 API 中使用弱类型集合。

  不要在公共 API 中使用 ArrayList 或 List<T>。

  不要在公共 API 这种使用 Hashtable 或 Dictionary<TKey, TValue>。

  不要使用 IEnumerator<T>、IEnumerator 或实现了这两个接口之一的任何其他类型,除非是作为 GetEnumerator 方法的返回类型。

  不要在同一类型中同时实现 IEnumerator<T> 和 IEnumerable<T>。对非泛型接口 IEnumerator 和 Enumerable 来说也同样如此。

  要用最泛的类型来作为参数类型。大多数以集合为参数的成员都使用 IEnumerable<T> 接口。

  避免使用 ICollection<T> 或 ICollection 来做参数 - 如果其目的仅仅只是为了访问该接口的 Count 属性。

  不要提供可设置的集合属性。

  要用 Collection<T> 或其子类 - 如果属性或返回值表示可读写的集合。

  要用 ReadOnlyCollection<T> 或其子类,在少数情况下用 IEnumerable<T>,如果属性或返回值表示只读的集合。

  考虑使用泛型集合基类的子类,而不要直接使用该集合。

  考虑用 Collection<T> 或 ReadOnlyCollection<T> 的子类来作为常用方法和常用属性的返回值。

  考虑使用有键集合 - 如果集合这种存储的元素都有独一无二的键值(名字、ID 等等)。有键集合是一个能同时以整数值和键值为索引来访问的集合,在实现时通常会让它们派生自 KeyedCollection<TKey, TItem>。

  不要从集合属性或以集合为返回值的方法中返回 null。而要返回一个空集合或空数组。

  不要让属性返回快照集合,属性应该返回实况集合。

  要用快照集合或实况的 IEnumerable<T>(或它的子类)来表示不稳定的集合(也就是说,无需显式地修改就可能会发生改变的集合)。

  不要让属性返回快照集合,属性应该返回实况集合。

  要用快照集合或实况的 IEnumerable<T> (或它的子类)来表示不稳定的集合(也就是说,无需显式地修改就可能会发生改变的集合)。

  要在设计新的集合时实现 IEnumerable<T>。如果合理,还可以考虑实现 ICollection<T> 甚至 IList<T>。

  考虑实现非泛型集合接口(IList 和 ICollection)- 如果经常需要把集合传给以这些参数为输入的 API。

  避免为类型实现集合接口 - 如果类型的 API 很复杂,而且与集合的概念无关。

  不要继承自非泛型的集合基类,比如 CollectionBase。要使用 Collection<T>,ReadOnlyCollection<T>,以及 KeyedCollection<TKey, TItem>。

  要在为类型命名时添加“Dictionary”后缀 - 如果类型实现了 IDictionary 或 IDictionary<TKey, TValue> 接口。

  要在为类型命名时添加“Collection”后缀 - 如果类型实现了 IEnumerable(或它的任何子类)接口,并且类型表示的是一个元素列表。

  要在命名自定义的数据结构时,使用合适的数据结构名。

  避免在为集合抽象命名时添加代表其具体实现的后缀,比如“LinkedList”或“Hashtable”。

  考虑用集合元素的类型名作为集合名字的前缀。

  考虑给只读集合的名字添加“ReadOnly”前缀,如果今后有可能会增加与之对应的可写集合,或与之对应的可写集合在框架中已经存在。

 

8.4 DateTime 和 DateTimeOffset

  要使用 DateTimeOffset - 如果想要表示一个精确地时间点。例如,用它来计算现在的时间、事务开始的时间、文件修改的时间、记录事件的时间,等等。如果不知道时区,那么就使用 UTC。与 DateTime 更实用的场景相比,上述场景更加常见,因此在默认情况下应该使用 DateTimeOffset。

  要在任何不适合使用绝对时间点的情况下使用 DateTime,比如能适用于不同时区的商店开门的时间。

  要在不知道时区或有时候不知道时区的情况下使用 DateTime。如果数据来自老式系统,那么可能会发生这种情况。

  不要在能够使用 DateTimeOffset 的时候使用 DateTimeKind。

  要用 DateTime 来表示所有的日期(比如生日),并将时间部分设为 00:00:00.不要用 DateTimeOffset 来表示日期。

 

8.5 ICloneable

  不要实现 ICloneable。

  不要在公共 API 中使用 ICloneable。

  考虑为需要克隆机制的类型定义 Clone 方法。一定要在文档中明确说明该方法执行的是深复制还是浅复制。

  

8.6 IComparable<T> 与 IEquatable<T>

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

  要在实现 IEquatable<T>.Equals 时,同样遵循为覆盖 Object.Equals 而制定的规范。

  要在实现 IEquatable<T> 的同时覆盖 Object.Equals。

  考虑在实现 IEquatable<T> 的同时重载 operator == 和 operator !=。

  要在实现 IComparable<T> 的同时实现 IEquatable<T>。

  考虑在实现 IComparable<T> 的同时重载比较caozuofu.html" target="_blank">操作符(<、>、<=、>=)。

 

8.7 IDisposable

 

8.8 Nullable<T>

  考虑用 Nullable<T> 来表示那些可能不存在的值(比如可选的值)。举个例子,如果要从数据库中返回一个强类型的记录,并且其中有一个属性对应的是表中一个可有可无的列,那么就应该使用 Nullable<T>。

  不要使用 Nullable<T> - 除非在类似的情况下你会因为引用类型可以为 null 而考虑用引用类型来代替它。例如,不应该用 null 来表示可选参数。

  避免用 Nullable<bool> 来表示通用的具有三种状态的值。Nullable<bool> 应该只用来表示真正可选的布尔值:true、false 以及不可用。如果至少是想表示具有三种状态的值(例如 yes、no、cancel),那么可以考虑使用枚举

  避免使用 System.DBNull。要优先使用 Nullable<T>。

 

8.9 Object

  要在覆盖 Object.Equals 方法时,遵守它定义的契约。

  要在覆盖 Equaals 方法的同时覆盖 GetHashCode 方法。

  考虑在覆盖 Object.Equals 方法的同时实现 IEquatable<T> 接口。

  不要从 Equals 方法中抛出异常

  要覆盖值类型的 Equals 方法。

  要通过实现 IEquatable<T> 来提供一个以该值类型本身为参数的 Equals 重载方法。

  考虑覆盖 Equals 以提供值相等语义 -  如果引用类型表示的是一个值。例如,对那些表示数值或其他数学试题的引用类型来说,可以考虑覆盖 Equals 方法。

  不要为可变的引用类型实现值相等语义。

  要覆盖 GetHashCode 方法 - 如果覆盖了 Object.Equals 方法。

  要确保对任何两个对象来说,如果 Object.Equals 方法返回 true,那么它们的 GetHashCode 方法的返回值也应该相同。

  要竭尽所能让类型的 GetHashCode 方法产生随机分布的散列码。

  要确保无论怎么更改对象,GetHashCode 都会返回完全相同的值。

  避免从 GetHashCode 方法中抛出异常。

  要覆盖 ToString 方法 - 只要能返回既有用,又易于让人阅读的字符串。

  要尽量让 ToString() 方法返回短小的字符串。

  考虑为每一个实例返回一个独一无二的字符串。

  要使用易于阅读的名字,而不要使用虽然独一无二,但却让人无法理解的 ID。

  要在返回与区域性有关的信息时,根据当前线程的区域性来对字符串进行格式化。

  要提供重载方法 ToString(string format) 或实现 IFormattable 接口 - 如果 ToString() 方法返回的字符串与区域性有关,或者有多种方法来对字符串进行格式化。例如,DateTime 既提供了重载方法,又实现了 IFormattable 接口。

  不要从 ToString() 方法返回空字符串或 null。

  避免从 ToString() 方法中抛出异常。

  要确保 ToString() 方法不会产生副作用。

  要通过 ToString() 的覆盖方法来报告与安全性有关的信息,前提是必须先获得相应的许可。如果无法获得许可,那么应该在返回的字符串中去除对安全性有关的信息。

  考虑让 ToString 方法输出的字符串能够为该类型的解析方法正确地解析。

  

8.10 序列化

  要在设计心得类型时考虑到序列化。

  考虑让类型支持数据协定序列化 - 如果需要在 Web 服务中使用该类型,或需要在 Web 服务中对该类型进行持久化。

  考虑让类型只支持 XML 序列化,或同时支持数据协定序列化和 XML 徐丽华 - 如果需要在徐丽华类型时生成的 XML 的格式有更多的控制。

  考虑让类型支持运行时序列化 - 如果需要跨越 .NET Remoting 的边界传输类型。

  不要仅仅为了进行一般的持久化而支持 XML 序列化或运行时序列化。应该优先支持数据协定序列化。

  考虑将类型中的成员定义为公有的 - 如果类型会被用于不完全可信的环境。

  要为所有应用了 DataMemberAttribute 的属性实现 getter 和 setter。为了能够让数据协定序列化程序对类型进行序列化,属性必须有 getter 和 setter。如果类型不会用于不完全可信的环境中,那么 getter 和 setter 中的一个或两个可以不是公有的。

  要用序列化毁掉函数来对反序列的实例进行初始化。

  考虑使用 KnownTypeAttribute 来表示那些在反序列化复杂的对象图时应该会用到的具体类型。

  要在创建或改变可序列化的类型时考虑向后兼容性和向前兼容性。

  考虑为了支持新老版本的双向转换而实现 IExtensibleDataObject。

  避免在设计类型时特别考虑 XML 序列化,除非有强烈的理由要对生成的 XML 内容加以控制。XML 序列化技术已经被前面介绍的数据协定序列化技术所取代。

  考虑实现 IXmlSerializable 接口 - 如果应用 XML 序列化修饰属性后生成的 XML 内容还不能满足需要。这个接口有两个方法,ReadXml 和 WriteXml,可以用他们来完全控制生成的 XML 内容。还可以给类型应用 XmlSchemaProviderAttribute 来对生成的 XML 架构加以控制。

  考虑支持运行时序列化 - 如果类型会被用于 NET Remoting。例如,由于 System.AddIn 命名空间用到了 .NET Remoting,因此在 System.AddIn 的外接程序(add-in)之间传输的所有类型都必须支持运行时序列化。

  考虑实现运行时序列化模式 - 如果想要完全控制序列化的整个过程。例如,想在序列化或反序列的时候进行数据转换。

  要将序列化构造函数定义为受保护的,并提供两个参数,参数的类型和命名要和下面的样例代码完全相同。

  要显式地实现 ISerializable 接口的成员。

  要给 Iserializable.GetObjectData 的实现应用一个链接要求,这样做是为了保证只有完全可信的代码和运行时序列化程序才能访问该成员。

 

8.11 Uri

  要使用 System.Uri 来表示 URI 和 URL 数据。

  考虑为最常用的带 System.Uri 参数的成员提供基于字符串的重载成员。

  不雅不假思索地为所有基于 System.Uri 的成员提供基于字符串的重载成员。

  要调用基于 System.Uri 的重载成员 - 如果有的话。

  不要在字符串中存储 URI/URL 数据。

  

8.12 System.Xml 的使用

  不要用 XmlNode 或XmlDocument 来表示 XML 数据。要尽量使用 IXPathNavigable、XmlReader、XmlWriter 或 XNode 的子类型。XmlNode 和 XmlDocument 的设计目的并不是为了公开暴露给外界的 API。

  要在接受 XML 或返回 XML 的成员中,以 XmlReader、IXPathNavigable 或 XNode 的子类型为输入或输出。

  不要从 XmlDocument 派生子类 - 如果想要创建的类型表示下层对象模型或数据源的 XML 视图。

  

8.13 相等性操作符

  

上一篇: 使用XmlWriter写Xml 下一篇: 没有下一篇了!
发表评论
用户名: 匿名