Effective C#原则7: 选择恒定的原子值类型数据

恒定类型(immutable types)其实很简单,就是一但它们被创建,它们(的值) 就是固定的。如果你验证一些准备用于创建一个对象的参数,你知道它在验证状 态从前面的观点上看。你不能修改一个对象的内部状态使之成为无效的。在一个 对象被创建后,你必须自己小心翼翼的保护对象,否则你不得不做错误验证来禁 止改变任何状态。恒定类型天生就具有线程完全性的特点:多访问者可同时访问 相同的内容。如果内部状态不能修改,那么就不能给不同的线程提供查看不一致 的数据视图的机会。恒定类型可以从你的类上安全的暴露出来。调用者不能修改 对象的内部状态。恒定类型可以很好的在基于哈希代码的集合上工作。以 Object.GetHashCode()方法返回的值,对同一个实例是必须相同的(参见原则10) ,而这正是恒定类型总能成功的地方。

并不是所有的类型都能成为恒定 类型的。如果它可以,你需要克隆一个对象用于修改任何程序的状态了。这就是 为什么同时推荐使用恒定类型和原子类型数据了。把你的对象分解为自然的单一 实体结构。一个Address类型就是的,它就是一个简单的事,由多个相关的字段 组成。改变其中一个字段就很可能意味着修改了其它字段。一个客户类型不是一 个原子类型,一个客户类型可能包含很多小的信息块:地址,名字,一个或者多 个电话号码。任何一个互不关联的信息块都可以改变。一个客户可能会在不搬家 的情况下改变电话号码。而另一个客户可能在搬了家的情况下保留原来的电话号 码。还有可能,一个客户改变了他(她)的名字,而没有搬家也没有改电话号码。 一个客户类型就不是原子类型;它是由多个不同的恒定的组成部份构成的:地址 ,名字,以及一个成对出现的电话号码集合。原子类型是单一实体:你很自然的 用原子类型来取代实体内容。这一例外会改变它其中的一个组成字段。

下面就是一个典型的可变地址类的实现:

// Mutable Address structure.
public struct Address
{
 private string  _line1;
 private string _line2;
 private string _city;
 private string _state;
 private int  _zipCode;
 // Rely on the default system-generated
 // constructor.
  public string Line1
 {
  get { return _line1; }
   set { _line1 = value; }
 }
 public string Line2
  {
  get { return _line2; }
  set { _line2 = value; }
 }
 public string City
 {
  get { return _city; }
  set { _city= value; }
 }
 public string State
 {
  get { return _state; }
  set
   {
   ValidateState(value);
   _state = value;
   }
 }
 public int ZipCode
 {
  get { return _zipCode; }
  set
  {
   ValidateZip( value );
   _zipCode = value;
  }
 }
 // other details omitted.
}
// Example usage:
Address a1 = new Address( );
a1.Line1 = "111 S. Main";
a1.City = "Anytown";
a1.State = "IL";
a1.ZipCode = 61111 ;
// Modify:
a1.City = "Ann Arbor"; // Zip, State invalid now.
a1.ZipCode = 48103; // State still invalid now.
a1.State = "MI"; // Now fine.

时间: 2024-11-02 11:57:53

Effective C#原则7: 选择恒定的原子值类型数据的相关文章

Effective C#原则8:确保0对于值类型数据是有效的

.Net系统默认所有的对象初始化时都为0.这并没有提供一个方法来预防其他 程序员创建的值类型数据的实例在初始化是都是0.请让你的数据类型默认值也 是0. 一个特殊情况是在枚举类型数据中.决不要创建一个不包括0在内 的枚举类型.所有的枚举类型都是从System.ValueType派生的.枚举类型的值是 从0开始的,但你可以改变这一行为: public enum Planet { // Explicitly assign values. // Default starts at 0 otherwis

Effective C#原则6:区别值类型数据和引用类型数据

值类型数据还是引用类型数据?结构还是类?什么你须要使用它们呢?这不 是C++,你可以把所有类型都定义为值类型,并为它们做一个引用.这也不是 Java,所有的类型都是值类型.你在创建每个类型实例时,你必须决定它们以什 么样的形式存在.这是一个为了取得正确结果,必须在一开始就要面对的重要决 定.(一但做也决定)你就必须一直面对这个决定给你带来的后果,因为想在后 面再对它进行改动,你就不得不在很多细小的地方强行添加很多代码.当你设计 一个类型时,选择struct或者class是件简单的小事情,但是,一

Effective C#原则12:选择变量初始化而不是赋值语句

(译注:根据我个人对文章的理解,我把initializer译为:初始化器,它是 指初始化语法,也就是在一个类里声明变量的同时,直接创建实例值的方法. 例:object m_o = new object();如果这段代码不在任何函数内,但在 一个类里,它就是一个初始化器,而不管你是把它放在类的开始还以结尾.) 一些类经常不只一个构造函数.时间一长,就难得让它的成员变量以及 构造函数进行同步了.最好的确保这样的事不会发生的方法就是:在声明就是的 时间就直接初始化,而不是在每个构造函数内进行赋值.而且

Effective C#原则2:为你的常量选择readonly而不是const

对于常量,C#里有两个不同的版本:运行时常量和编译时常量. 因为 他们有不同的表现行为,所以当你使用不当时,将会损伤程序性能或者出现错误 . 两害相权取其轻,当我们不得不选择一个的时候,我们宁可选择一个 运行慢一点但正确的那一个,而不是运行快一点但有错误的那个.基于这个理由 ,你应该选择运行时常量而不是编译时常量(译注:这里隐藏的说明了编译时常 量效率更高,但可能会有错误). 编译时常量更快更直接,但在可维护性 上远不及运行时常量.保留编译时常量是为了满足那些对性能要求克刻,且随着 程序运行时间

Effective C#原则45:选择强异常来保护程序

当你抛出异常时,你就在应用程序中引入了一个中断事件.而且危机到程序 的控制流程.使得期望的行为不能发生.更糟糕的是,你还要把清理工作留给最 终写代码捕获了异常的程序员.而当一个异常发生时,如果你可以从你所管理的 程序状态中直接捕获,那么你还可以采取一些有效的方法.谢天谢地,C#社区不 须要创建自己的异常安全策略,C++社区里的人已经为我们完成了所有的艰巨的 工作.以Tom Cargill的文章开头:"异常处理:一种错误的安全感觉, " 而且Herb Sutter,Scott Meyer

Effective C#原则40:根据需求选择集合

"哪种集合是最好的?"答案是:"视情况而定." 不同的集合有不同的性能,而且在不同的行为上有不同的优化..Net框架支持很 多类似的集合:链表,数组,队列,栈,以及其它的一些集合.C#支持多维的数 组,它的性能与一维的数组和锯齿数组都有所不同..Net框架同样包含了很多特 殊的集合,在你创建你自己的集合类之前,请仔细参阅这些集合.你可以发现很 多集合很快,因为所有的集合都实现了ICollection接口.在说明文档中列出了 所有实现了ICollection接口的集合

Effective C#原则27:避免使用ICloneable

ICloneable看上去是个不错的主意:为一个类型实现ICloneable接口后就可 以支持拷贝了.如果你不想支持拷贝,就不要实现它. 但你的对象并不 是在一个"真空"的环境中运行,但考虑到对派生类的些影响,最好 还是对ICloneable支持.一但某个类型支持ICloneable, 那么所有的派生类都必 须保持一致,也就是所有的成员必须支持ICloneable接口或者提供一种机制支持 拷贝.最后,支持深拷贝的对象,在创建设计时如果包含有网络结构的对象,会 使拷贝很成问题.IClon

Effective C#原则23:避免返回内部类对象的引用

你已经知道,所谓的只读属性就是指调用者无法修改这个属性.不幸运的是 ,这并不是一直有效的.如果你创建了一个属性,它返回一个引用类型,那么调 用者就可以访问这个对象的公共成员,也包括修改这些属性的状态.例如: public class MyBusinessObject { // Read Only property providing access to a // private data member: private DataSet _ds; public DataSet Data { get

Effective C#原则10:明白GetHashCode()的缺陷

这是本书中唯一一个被一整个函数占用的原则,你应该避免写这样的函数. GetHashCode()仅在一种情况下使用:那就是对象被用于基于散列的集合的关键 词,如经典的HashTable或者Dictionary容器.这很不错,由于在基类上实现的 GetHashCode()存在大量的问题.对于引用类型,它可以工作,但高效不高:对 于值类型,基类的实现经常出错.这更糟糕.你自己完全可以写一个即高效又正 确的GetHashCode().没有那个单一的函数比GetHashCode()讨论的更多,且令人 困惑