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

转载 2007年09月30日 13:27:00

转:http://dev.csdn.net/author/Knight94/5582b364fc744be09bca2dca36786322.html

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

 

首先来解释一下标题,原标题为《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,这方面我就不多说了,参看我以前写的文章就可以明白(这里的目的也就是一点,防止局部破坏原子类型的分支)。

 

Effective C# Item6:明辨值类型和引用类型的使用场合

可能是受到Java的影响,我在转向C#后,一直没有注意区分过值类型和引用类型,不论是编写新代码还是重构旧代码时,如果发现有一些信息需要独立出来时,一直都是以新建类的方式进行,很少考虑使用结构体(我到目...

Effective C# Item19:定义并实现接口优于继承类型

这个话题不仅仅是针对.NET的,在其他面向对象语言的环境中,例如Java,都会有接口和抽象类,对于究竟是选择接口还是抽象类,已经有了太多的讨论,包括设计模式中都有了一条设计原则:组合优于继承,虽然这条...

[Effective Java Distilled] Item 3 通过使用私有构造方法或者枚举类型来强化单例属性

关于Effective Java Distilled: 《Effective Java》这本书我断断续续的读了近两遍,里面的内容挺有深度,对提高工程代码质量也非常有帮助。我打算慢慢的整理出来一个...

Effective JavaScript Item 46 优先使用数组而不是Object类型来表示有顺序的集合

本系列作为Effective JavaScript的读书笔记。   ECMAScript标准并没有规定对JavaScript的Object类型中的属性的存储顺序。   但是在使用for..in...

《Effective C++》读书笔记之item47:请使用traits classes表现类型信息

1.使用traits技术可以在编译期间获取某些类型信息,它要求对内置类型和用户自定义类型表现得一样好。标准模板库是把traits信息放到模板中,其中针对迭代器的被命名为iterator_traits,...

Effective Java Item3:使用私有构造方法或者枚举类型实现单例(转自sunjavaduke)

Item3 Enforce the singleton property with a private constructor or an enum type 使用私有构造方法或者枚举类型实现单例。...

【Effective Java】Ch2_创建销毁对象:Item7_避免使用finalize方法

Finalizer通常是不可预测的、危险的、不必要的。使用finalizer会导致不稳定的行为、低下的性能、以及可移植问题。Finalizer也有其可用之处,本文稍后会做介绍,但是作为一个首要法则,你...

[Effective Java Distilled] Item 3 通过使用私有构造方法或者枚举类型来强化单例属性

关于Effective Java Distilled: 《Effective Java》这本书我断断续续的读了近两遍,里面的内容挺有深度,对提高工程代码质量也非常有帮助。我打算慢慢的整理出来一个...

Effective Java Item7:Avoid Finalizers,解释为什么finalize是不安全的,不建议使用

在讨论如何回收堆外内存的时候,提到“NIO中direct memory的释放并不是通过finalize(),因为finalize不安全而且影响能”。Effective Java一书中也提到:Avoid...

Effective Java Item7-不使用Finalizers

禁用activity中finalize方法
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:转:《Effective C#》Item 7:推荐使用不可改变的原子值类型
举报原因:
原因补充:

(最多只允许输入30个字)