基本类型、引用类型、值类型——,CLR via C#

大家都说,CLR via C# 翻译的不好,也就没买,看英文原版,一边看一边想写笔记,但是懒惰让自己一直懒于动笔,随便写写吧,总比不写强。

每种语言都有其基本数据类型。

C#也不例外,但是这里不同之处在于多出了个.net平台。

所以,C#每个基本数据类型都对应一个FCL类。但不一定都兼容CLS。

C#规范说要尽量用C#约定的基本类型表示符,Jeffrey不这么认为,他认为应该尽量使用FCL提供的具体类名,这样不会产生歧义。

另外关于基本数据类型之间的转化,Jeffrey说,这个不能遵循类继承关系规则了,编译器知道该怎么办。(佩服老外就在于这种地方,这个事他会拿出来单独给你说说)

转化规则不细说了,因为我自己用C#,有句话必须说“在小数转化为整数时,C#总是舍掉小数部分” 数据溢出检查不多说了,缺省不检查。

引用类型、值类型:

之前一直没有太过于留意FCL提供的类中,哪些是引用类型,哪些是数字类型,还一直以为除了基本类型和枚举类型意外都是引用类型,Jeffrey倒是给提了个醒,说一般称其为结构的是值类型,结构是值类型这我清楚,可是一直没留意“结构”这个词。

内存分配的事就不多说了,比较清楚。

这里说说自定义值类型,通常也就是结构了,Jeffrey说,如果定义结构,那么其内定义的字段在程序运行期间不会被修改,或则说不能对其修改。刚开始不理解这句话的用意,看到后来的装箱和拆箱才明白了,因为很多人意识不到拆装箱,或则说有时候有潜伏的拆装箱操作,如果对内存分配和拆装箱基本原理不很清楚,往往会有不正确的赋值预期。另外定义的结构,尽可能的要小,如果要大点也可以,但就不要当参数传递了,因为这会带来性能损失。

老实说,什么时候应该将一个类定义为结构,自己也学习过,但是上两点说法倒是头回听说。

拆箱、装箱:

老话题了,看上一章的时候了解到引用类型,有两个特殊的变量,一个就是类型指针,另外一个就是同步索引,这里我想说的是同步索引,因为有同步索引的存在所以,引用类型可以用来做同步锁,而值类型不可以,原因就在于此。(似乎懂了)

泛型的问题暂不多说了。

关于明显的需要类型转换的地方,发生拆装箱子,是易于理解的。但是对值类型调用方式时发生的潜在拆装箱倒是没注意,例如 Point p;p.GetType();就会发生装箱行为,因为GetType方法直接继承于Object,而值类型重载的虚方法或自己的方法调用则不会发生装箱行为。

对象Equal检查:

object提供的Equal虚方法,用来识别两个对象是否是指向同一个对象,但是Jeffrey说,如果你真是这个目的最好不要用Equal虚方法,最好用静态的ReferenceEqual,为什么呢?因为虚方法是可以被覆写的,覆写后是否还是这样一层意思就不一定了。例如,你可以判断两个对象是否值相等,基本数据类型就是这么覆写的,字符串也是这么覆写的。所以是比较两个对象是否相等还是指向同一个对象,是要仔细计较一下的。

object Hash Code

对哈希表为什么叫哈希表一直不清楚,对object的GetHashCode方法,更是不知道怎么用。

看过这一节之后,略有明白:

Microsoft为了实现对不同对象的区分,以方便将其放在HashTable内,通过hashcode找对对应 键/值 对,所以为object设置了这样一个GetHashCode的方法,获取一个唯一的哈希码区分,object内部的算法不清楚,但是它提供的是虚方法,你自己可以覆写自己的区分方式,当然这要遵循一定的原则。另外,如果覆写Equal方法的话,就一定要覆写GetHashCode方法,原因是hashtable判断两个对象是否Equal需要用到该方法,这里的对象是指key对象。

需要特别说明的是,这里获取的hash code 可以在某次应用中用于区分对象,但是不能将某次获取的hashcode作为永久标志应用,它是会变的(例如算法的重写)。

如何写获取HashCode的方法,以及实现规则就不多说了。