王朝网络
分享
 
 
 

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

王朝c#·作者佚名  2007-09-21
宽屏版  字体: |||超大  

首先来解释一下标题,原标题为《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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有