首先来解释一下标题,原标题为《Prefer Immutable Atomic Value Type》,因此对于标题的理解要分成三部分,第一部分为不可改变,第二部分为原子,最后一个部分为值类型。最后一部分,我不多说了,限制此章适用的范围。对于什么是不可改变类型,这里的意思是指此类型的变量一旦产生其成员就不能发生变化。至于原子类型,我以前在CSDN也经常提到,例如保证操作的原子性之类的语句,那么一个原子类型,其的子成员为不可分割的一部分,不能单独被操作。

听了标题解释,难免有些人会问,为什么要加上这样的限制,或者说这样做的好处是什么。为了解开这个疑团,我用一个例子来说明,去定义一个电话号码的值类型,一般形式如下:

public struct Phone

{

private string strCountry_Code;

private string strCity_Code;

private string strPhone_Number;

public string Country_Code

{

get{ return strCountry_Code; }

set{ strCountry_Code = value;}

}

public string City_Code

{

get{ return strCity_Code; }

set{ strCity_Code = value;}

}

public string Phone_Number

{

get{ return strPhone_Number; }

set{ strPhone_Number = value;}

}

// Constructor

public Phone( string sCountry_Code, string sCity_Code, string sPhone_Number )

{

strCountry_Code = sCountry_Code;

strCity_Code = sCity_Code;

strPhone_Number = sPhone_Number;

}

}

这样去初始化一个Phone类型变量的话,同时也可以做类似如下的相关操作。

Phone myPhone = new Phone( "086", "010", "66666666" );

myPhone.City_Code = "021";

myPhone.Phone_Number = "777777777";

大多数人觉得如上的代码没有什么问题,不过稍微明眼的人看了如上的代码,就会立刻觉得有潜在的危险。作为一个Phone类型变量来说,国家区号,城市区号,以及电话号码来说是一个整体。因此动态修改其中的某一个值,会造成其他两个无效。也就是说如上的代码直接修改City_Code的时候,对于myPhone来说其他两个变量Country_Code以及Phone_Number来说,此时是无效的。不过这种错误在单线程中不是很明显,但是在多线程中是致命的,而且很难查出来。有人可能会说了,在修改的时候加上Lock语句或者互斥标识来避免。这样是可以避免,但是试问一下,类型是你创建的,你怎么要求别人在使用你这个类型的时候做过多的操纵呢,为什么你不在创建此类型的时候就直接把这条路堵死。如果明白了这一点,就理解了这篇文章推荐的目的,即与其后期增加代码弥补,不如在前期就编写正确的代码。

知道这样做的原因,接下来就是如何去实现。不过在实现之前,要区分什么样的数据类型可以定义成不可变的原子类型。也就是说,你如何区分一个类型是一个整体,而且每个分支不能独立于整体而存在。例如对于联系方式这个类型来说,它包括电话号码、住址等等。它可以看为一个整体,但是分支可以脱离这个整体而存在,因此它不是一个原子类型。对于如何具体区分,很难有一个统一的方法,毕竟适应的环境不同,操作以及实现也不同。不过对于原子类型,有一个唯一判断方式,就是每个分支能否独立于整体而被操作,这个的是与否决定是否为原子类型。

那么如何去定义一个不可变的原子值类型呢,大致要对原有的类型做两个处理,一个就是把所有成员加上readonly标示,即只能在构造函数中被修改;另一个就是删除属性set部分。对于Phone这个类型来说,经过处理后,正确的形式如下:

public struct Phone

{

private readonly string strCountry_Code;

private readonly string strCity_Code;

private readonly string strPhone_Number;

public string Country_Code

{

get{ return strCountry_Code; }

}

public string City_Code

{

get{ return strCity_Code; }

}

public string Phone_Number

{

get{ return strPhone_Number; }

}

// Constructor

public Phone( string sCountry_Code, string sCity_Code, string sPhone_Number )

{

strCountry_Code = sCountry_Code;

strCity_Code = sCity_Code;

strPhone_Number = sPhone_Number;

}

}

这样对于一个Phone类型变量,只能通过new来创建(也就是说在输入三个有效的数据后,一个Phone类型变量才能产生)。

在此有人会问,除了new是否还有其他方法来进行修改。这是没有任何问题的,首先你只要理解了原子类型的意义,保证分支不会单独被修改即可,因此可以实现类似于“Phone.Parse”或者“Phone.From”之类的函数来形成一个新的Phone变量。

在实现不可变的原子值类型的时候,要防止类型中包括引用类型分支的时候,在进行成员赋值的时候,防止浅copy,这方面我就不多说了,参看我以前写的文章就可以明白(这里的目的也就是一点,防止局部破坏原子类型的分支)。

http://blog.csdn.net/Knight94/archive/2006/07/01/861383.aspx

http://blog.csdn.net/Knight94/archive/2006/06/04/772886.aspx

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Knight94/archive/2006/07/27/985552.aspx

转载于:https://www.cnblogs.com/Sue_/articles/1656554.html

《Effective C#》Item 7:推荐使用不可改变的原子值类型相关推荐

  1. [转]Effective C# 原则7: 选择恒定的原子值类型数据

    恒定类型(immutable types)其实很简单,就是一但它们被创建,它们(的值)就是固定的.如果你验证一些准备用于创建一个对象的参数,从前面的观点上看, 你知道它在合法(valid)状态.你不能 ...

  2. 《Effective C#》读书笔记——条目19:保证0为值类型的有效状态.NET资源管理

    .NET系统的默认初始化过程会将所有的对象设置为0.我们就会难免创建出一个初始化为0值的值类型,所以我们应该将0作为类型的默认值,可以避免一些不必要的Bug. 1.将0设置为枚举的有效值 使用枚举时我 ...

  3. Effective C#: Item 1 Always use properties instead of accessible data members

    Effective C#: Item 1 Always use properties instead of accessible data members Item 1: 当设计类时,永远用Prope ...

  4. Effective C#: Item 3: Prefer the is or as Operators to Casts

    Item 3: Prefer the is or as Operators to Casts C#是强类型语言.我们要尽量避免类型转换. 有时我们必须要在runtime检查一个变量的类型.比如有时你要 ...

  5. 读书笔记 effective c++ Item 41 理解隐式接口和编译期多态

    1. 显示接口和运行时多态 面向对象编程的世界围绕着显式接口和运行时多态.举个例子,考虑下面的类(无意义的类), 1 class Widget { 2 public: 3 Widget(); 4 vi ...

  6. Effective C# 原则8:确保0对于值类型数据是有效的(翻译)

    Effective C# 原则8:确保0对于值类型数据是有效的 Ensure That 0 Is a Valid State for Value Types .Net系统默认所有的对象初始化时都为0. ...

  7. c语言函数实参是赋值语句,c语言说形参不能改变实参的值,为什么这个赋值语句可以...

    c语言说形参不能改变实参的值,为什么这个赋值语句可以0 cpystr(q1; printf(" cpystr(char *p1,*q2,char *p2) {while(*p2++=*p1+ ...

  8. python 推荐与该用户喜欢的电影类型相同的电影

    假设已有大量用户对若干电影的评分数据,现有某用户,也看过一些电影并进行过评分,要求根据已有打分数据为该用户进行精准推荐.要求尽量推荐与该用户喜欢的电影类型相同的电影(或者说,根据与该用户爱好最相似的用 ...

  9. java 不可修改的集合对象_java集合:关于hashmap存储一个对象,中间改变对象的值,为什么再remove不能用新名字来删除...

    代码如下:publicclassDemo1{publicstaticvoidmain(String[]args){HashSetsc=newHashSet<>();bookbook1=ne ...

最新文章

  1. 设计模式(19)-Observer Pattern
  2. java字符_Java String 类
  3. 计算机网络09年考研题,计算机网络考研真题及答案
  4. windows 下安装 scrapy报错:error: Unable to find vcvarsall.bat
  5. 5 Transforms 转移 笔记
  6. Android的历史、版本与开发
  7. ×××背景知识技术介绍
  8. SHELL下获得指定进程的进程号,并截取为整数
  9. 计算机网络——数据通信系统(三)
  10. Android开发 无线Wifi+WifiUtil工具类,直面秋招
  11. 计算机专业英文授课,计算机专业全英文授课分析
  12. 夏时制英国和中国的时差是多少?伦敦与北京时差是多少?
  13. 洛谷【入门4】数组 P2615 [NOIP2015 提高组] 神奇的幻方
  14. java搭建直播商城VR全景商城 saas商城 b2b2c商城 o2o商城 积分商城 秒杀商城 拼团商城 分销商城
  15. AnyRTC将携互动直播连线2016杭州·云栖大会
  16. Netlogo 之Java 调用netlogo 程序
  17. ARFoundation之路-光照估计
  18. mysql 生成序号 且自增
  19. 前端培训出来的人,公司怎么看呢?
  20. Linux安装MySQL8.0.29,并使用Navicat连接

热门文章

  1. 第十章:基本数据结构(2)
  2. 【css】谈谈 css 的各种居中——读编写高质量代码有感
  3. [Android疑难杂症]动态设置TextView的width不起作用
  4. Oracle安装与操作系统用户组
  5. Android UI开发第三十九篇——Tab界面实现汇总及比较
  6. 《『若水新闻』客户端开发教程》——14.代码编写(6)
  7. 瞬间之美:Web 界面设计如何让用户心动
  8. HTML5 CSS3编程入门经典 ((美)Rob Larsen) pdf扫描版
  9. Launch和Shut Off操作详解 - 每天5分钟玩转 OpenStack(30)
  10. sublime theme color