CLR via C# 第五章学习记录(更新中)

1.设置全局溢出检查,项目属性->生成->高级->检测运算上溢/下溢
2.局部使用溢出检测
Byte b = 100;
b = checked((Byte)(b + 200));// 不检测溢出
checked// 检测溢出代码段
{
Byte b = 100;
b = (Byte)(b + 200);
}
——————————————————————————
UInt32 invalid = unchecked((UInt32)(-1));// 检测溢出
unchecked// 不检测溢出代码段
{
Byte b = 100;
b = (Byte)(b + 200);
}

CLR支持2种类型:引用类型和值类型

引用类型总是从托管堆分配,C#的new操作符返回对象内存地址——即指向对象的内存地址。使用引用类型必须留意性能问题。注意4个事实
1.内存必须从托管堆分配(new的时候进行内存分配)
2.堆上分配的每个对象都有一些额外成员,这些成员必须初始化。
3.对象中的其他字节(为字段而设)总是设为0
4.从托管堆分配对象时,可能强制执行一次垃圾回收
引用类型和值类型的区别:
任何称为“类”的类型都是引用类型。(如:System.Exception类,System.IO.FileStream类以及System.Radom类)
所有值类型都称为结构或者枚举,(如:System.Int32结构,SystemBoolean结构,SystemDecimal结构,System.TimeSpan结构,System.DayOfWeek枚举,System.IO.FileAttributes枚举以及System.Drawing.FontStyle枚举)所有结构都是抽象类型System.ValueType的直接派生类。System.ValueType本身又直接从System.Object派生。根据定义,所有值类型都必须从System.ValueType派生。所有枚举都是从System.Enum抽象类型派生,后者又从System.ValueType派生。
class SomeRef { public Int32 x;}// 所有的class都是引用类型
struct SomeVal { public Int32 x;}// 所有的Struct都是值类型
static void ValueTypeDemo() {
SomeRef r1 = new SomeRef();// 在堆上分配
SomeVal v1 = new SomeVal();// 在栈上分配
r1.x = 5; // 提领指针
v1.x = 5; // 在栈上修改
Console.WriteLine(r1.x); // 显示5
Console.WriteLine(v1.x); // 显示5
//
SomeRef r2 = r1; // 只复制引用(指针/地址)
SomeVal v2 = v1; // 在栈上分配并复制成员
r1.x = 8; // r1.x和r2.x都会更改
v1.x = 9; // v1.x会更改,v2.x不变
Console.WriteLine(r1.x); // 显示8
Console.WriteLine(r2.x); // 显示8
Console.WriteLine(v1.x); // 显示9
Console.WriteLine(v2.x); // 显示5
SomeVal v1=new SomeVal(); //在栈上分配,所有的字段初始化为0(已初始化)
=>SomeVal v1; //在栈上分配,同样初始化为0(会认为v1未赋值)
}

将值类型变量赋给另一个值类型变量,会逐行逐字段的复制,将引用类型的变量赋给另一个引用类型的变量只复制内存地址。
装箱是将值类型转换成引用类型,拆箱是将引用类型转换成值类型
public static void Main() {
Point p;
p.x = p.y =1;
Object o = p; // 对p装箱:o引用已装箱实例
p = (Point) o; // 对o拆箱,将字段从已装箱实例复制到栈变量中,C#编译器将生成一条IL指令对o拆箱(获取毅装箱实例中的字段的地址),并生成另一条指令将这些字段从堆复制到基于栈的变量p中
p.x = 2; // 更新栈变量状态
o = p; // 对p装箱:o引用新的已装箱实例
}

要获取对值类型实例的引用,实例就必须装箱,将值类型实例传给需要获取引用类型的方法,就会发生这种情况

public sealed class Program {
public static void Main() {
Int32 v = 5; // 创建未装箱的值类型变量
#if INEFFICIENT
// 编译下面这一行,v被装箱3次,浪费时间和内存
Console.WriteLine("{0},{1},{2}", v, v, v);
#else
// 下面代码结果一样,但无论执行速度,还是内存利用,都比前面代码更胜一筹
Object o = v; // 对v进行手动装箱(1次)
// 编译下面这行不发生装箱
Console.WriteLine("{0},{1},{2}", o, o, o);
}
}

 

posted @ 2017-02-20 20:52  xiao贝  阅读(374)  评论(0编辑  收藏  举报