《CLR via C#》读书笔记--基元类型、引用类型和值类型
编程语言的基元类型
编译器直接支持的数据类型称为基元类型
。基元类型
直接映射到Framework
类库中存在的类型。例如:C#中的int
直接映射到System.Int32
类型。下表给出了C#基元类型
与对应的FCL
类型
C#规范中写道从风格上说,最好是使用关键字,而不是使用完整的系统类型名称
,但作者认为最好使用FCL类型名称
许多开发人员纠结于到时使用
string
还是String
。由于C#的string
关键字直接映射到System.String
,所以两者没有区别。有些人说应用程序在32位操作系统运行,int代表32位整数;在64位系统运行,int代表64位系统。这是错误的
。C#的int始终映射到System.Int32
所以始终代表32位系统。
C#对操作结果总是进行截断
,而不是向上取整。
除了转型,基本类型还能写成字面值
,就是类型本身的实例。
Console.WriteLine(123.ToString()+456.ToString()); //123456
编译器在编译时就能完成表达式求值,从而增强应用程序性能。
checked和unchecked基元类型操作
C#通过提供checked
和unchecked
操作符来提供这种灵活性。以下为使用了unchecked
操作符的例子:
Uint32 invalid = unchecked(UInt32)(-1);// OK
以下使用了checked
操作符;
Byte b = 100;
b =checked((Byte)(b+200)); // 抛出OverflowException异常
也可以这样使用:把需要检查的放到一个语句块中
checked{
Byte b = 100;
b = (Byte)(b+200);
}
建议:
- 尽量使用有符号数值类型,而不是无符号数值类型。这允许编译器检查更多的上溢、下溢错误。
- 写代码时,如果代码可能发生你不希望的溢出,就把这些代码放到
checked
语句中。同时捕捉OverflowException
异常,得体的从错误中恢复。 - 写代码时,将允许发生溢出的代码放到
unchecked
块中,比如在计算校验和时。
引用类型和值类型
CLR
支持两种类型:引用类型
和值类型
。引用类型
从托管堆
分配,C#的new
操作符返回对象的内存地址--即指向对象数据的地址。使用引用类型必须清楚以下四个事实
- 内存必须从托管堆分配
- 堆上分配的每个对象都有一些额外成员,这些成员必须初始化
- 对象中的其它字节总是设为零
- 从托管堆分配对象时,可能强行执行一次垃圾回收。
使用值类型能缓解
托管堆的压力
任何称为类
的类型都是引用类型
,如System.Exception
、System.IO.FileStream
类等。所有值类型
都被称为结构
或枚举
,如System.Int32结构
、Boolean结构
、Decimal结构
、System.TimeSpan结构
等。所有结构都是System.ValueType
的直接派生类。System.ValueType
又直接从System.Object
派生。所有枚举从System.Enum
派生,后者从System.ValueType
派生。
演示引用类型和值类型的区别
引用类型和值类型让我想起了报纸和网址的区别。使用引用类型
就像给了别人一个网址,你在这边修改数据,别人看到的也会修改。而值类型
的话更像是给了别人一份报纸的拷贝,你在这边修改,只是像在报纸上做笔记,别人不能看到修改。有些不是很恰当,看上面的例子就会理解了。
如果使用new
操作符,C#会认为实例已被初始化:
SomeValue v1 = new SomeValue();
Int32 a = v1.x;//可以通过编译,v1已被初始化为0
而如果
SomeValue v1;
Int32 a = v1.x;//使用了可能未赋值的字段x
对于许多值类型,我们都建议将全部字段标记为readonly
值类型和引用类型的区别:
- 值类型有两种形式:
未装箱
和已装箱
,引用类型总是处于已装箱
模式 - 值类型重写了
Equals
和GetHashCode
方法。由于这个默认实现存在性能问题,在定义自己的值类型时,应该重写Equals
和GetHashCode
方法,并提供他们的显示实现 - 值类型能不应引入任何虚方法,不能是抽象的方法
- 引用类型变量中包含
堆中对象的地址
,变量创建时会被初始化为null
,表明当前不是有效对象。试图使用null
引用类型会跑出NullReferenceException
异常,相信初学者会经常遇到。 - 值类型复制会逐字段的复制,引用类型复制只复制内存地址
- 两个或多个引用变量可能引用堆中同一对象,而值类型不会,它自成一体。
值类型的装箱和拆箱
public static void Go() {
ArrayList a = new ArrayList();
Point p; // Allocate a Point (not in the heap).
for (Int32 i = 0; i < 10; i++) {
p.x = p.y = i; // Initialize the members in the value type.
a.Add(p); // Box the value type and add the
// reference to the Arraylist.
}
}
// Declare a value type.
private struct Point { public Int32 x, y; }
point
是值类型,添加到ArrayList
中要发生装箱,造成性能损失。
装箱
时要发生的事情:
- 在托管堆中分配内存。
- 值类型的字段赋值到新分配的内存
- 返回对象地址,现在改地址是对象引用,值类型成了引用类型。
注意
:FCL
现在包含一组新的泛型集合集。应该使用List
而不是ArrayList
。好处有:泛型集合类允许开发人员使用值类型时不需要对集合中的项进行拆箱和装箱(最重要);增强了编译时的类型安全性等等
拆箱的步骤:
- 获取已装箱Point对象中的各个Point字段的地址。
- 将字段包含的值复制到基于栈的值类型空间中。
第五章内容还剩下一半,明天发。顺便发下我的博客网址L:www.kuiblog.com,谢谢。一起交流
《CLR via C#》读书笔记--基元类型、引用类型和值类型的更多相关文章
- Clr Via C#读书笔记----基元线程同步构造
线程文章:http://www.cnblogs.com/edisonchou/p/4848131.html 重点在于多个线程同时访问,保持线程的同步. 线程同步的问题: 1,线程同步比较繁琐,而且容易 ...
- 2019.03.21 读书笔记 基元类型的Parse与TryParse 性能与建议
Parse转换失败时会抛出异常,耗损性能,如果转换成功,则与TryParse无差异.查看源码,tryparse的代码更多一些,在失败时,反而性能更优,主要是抛出异常耗损了性能.所以在不确定是用Tryp ...
- CLR via C#(02)-基元类型、引用类型、值类型
http://www.cnblogs.com/qq0827/p/3281150.html 一. 基元类型 编译器能够直接支持的数据类型叫做基元类型.例如int, string等.基元类型和.NET框架 ...
- [CLR via C#]引用类型和值类型
一.引用类型与值类型的区别 CLR支持两种类型:引用类型和值类型.引用类型总是从托管堆上分配的,C#的new操作符会返回对象的内存地址.使用引用类型时,必须注意到一些性能问题. 1)内存必须从托管堆上 ...
- 《CLR via C#》读书笔记(5)基元类型、引用类型和值类型
5.1 基元类型 编译器直接支持的数据类型称为基元类型(primitive type). 以下4行到吗生成完全相同的IL int a = 0; //最方便的语法 System.Int32 b = 0; ...
- CLR via #C读书笔记三:基元类型、引用类型和值类型
1.一些开发人员说应用程序在32位操作系统上运行,int代表32位整数:在64位操作系统上运行,int代表64位整数.这个说法是完全错误的.C#的int始终映射到System.Int32,所以不管在什 ...
- [Clr via C#读书笔记]Cp5基元类型引用类型值类型
Cp5基元类型引用类型值类型 基元类型 编译器直接支持的类型,基元类型直接映射到FCL中存在的类型. 作者希望使用FCL类型名称而避免使用关键字.他的理由是为了更加的清晰的知道自己写的类型是哪种.但是 ...
- CLR via C#深解笔记三 - 基元类型、引用类型和值类型 | 类型和成员基础 | 常量和字段
编程语言的基元类型 某些数据类型如此常用,以至于许多编译器允许代码以简化的语法来操纵它们. System.Int32 a = new System.Int32(); // a = 0 a = 1 ...
- <NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型
5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...
随机推荐
- 孙鑫MFC学习笔记:15多线程
15 1.进程地址空间 2.线程 3.CreateThread创建一个线程 4.CloseHandle关闭线程句柄,要在不再使用线程句柄的时候关闭,递减线程引用计数 5.编辑框默认不支持多行,需要打开 ...
- MySQL使用二进制日志恢复数据库
一.二进制日志简介 MySQL有不同类型的日志,其中二进制文件记录了所有对数据库的修改,如果数据库因为操作不当或其他原因丢失了数据,可以通过二进制文件恢复. 在my.ini文件中设置了log-bin, ...
- Exception raised during rendering: java.lang.System.arraycopy([CI[CII)V
最近下载一个新版本的adt-bundle,Android API是20. 把Plain Text控件往布局上面拖时,发现拖不上去,出现了下面的错误: Exception raised during r ...
- HDU 3328 Flipper 栈 模拟
首先想说,英语太烂这题读了很长时间才读懂......题意是说输入有几张牌,然后输入这些牌的初始状态(是面朝上还是面朝下),然后输入操作方式,R表示翻一下右边的牌堆,L表示翻一下左边的牌堆,直到最后摞成 ...
- ahjesus 单词单数-复数相互转换C#
看codesmith内置的模板在生成存储过程的时候有单复数的转换,用相同的函数名实现了一个 public static class StringUtil { /// <summary> / ...
- linux下安装redis的详细过程
先安装一些组件: yum -y install gcc gcc-c++ libstdc++-devel 下载并安装: # wget http://download.redis.io/releases/ ...
- Ratatype - 在线打字教程,提高打字速度
Ratatype 是一个在线的打字教程网站,帮助人们提高键盘输入速度.开始掌握你的技能,挑战你的朋友或得到一个打字的证书.如果打字慢会浪费你宝贵的时间.如果你的打字速度提高30%,您可以每天节省20分 ...
- about this
var name="window name"; var obj={ name:"obj name", getNameFunc:function(){ //thi ...
- 系统安装LOL等游戏后出现VS调试报错"无法调试""拒绝访问"之类的调试错误
一个问题抠得脑壳痛,度娘一番各种各样的答案.基本属于 1,调试权限被清0 2,文件权限问题 其中看到很多解决方案中提到"重启电脑"的说法.我也试了几次不行甚至游戏都卸载了.后来 ...
- Nessus常见问题整理
个别问题感谢大学霸__IT达人在Kali中文网的解答. 问题1: Kali自带Nessus产品注册失败 报Error(500):Activation failed 出现这个错误原因很多.其中有一个原 ...