标签:
书上一开头就说了一个概念
编译器直接支持的数据类型称为基元类型(primitive type)。
以下是基元类型.
C# Primitive Typ | FCL Type | CLS-Compliant |
sbyte | System.SBte | NO |
byte | System.Byte | YES |
short | System.Int16 | YES |
ushort | System.UInt16 | NO |
int | System.Int32 | YES |
uint | System.UInt32 | NO |
long | System.Int64 | YES |
ulong | System.UInt64 | NO |
char | System.Char | YES |
float | System.Single | YES |
double | System.Double | YES |
decimal | System.Decimal | YES |
object | System.Object | YES |
string | System.String | YES |
和基元类型对应的 就是Class 或者 复杂类型。
这些经常使用的基元类型,所以有一些简化的语法去操作他.
1 int i = 0;
2 Console.WriteLine(i);
3 Console.ReadKey();
.entrypoint
// 代码大小 15 (0xf)
.maxstack 1
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: ldloc.0
IL_0003: call void [mscorlib]System.Console::WriteLine(int32)
IL_0008: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
IL_000d: pop
IL_000e: ret
IL_0000 将所提供的 int32 类型的值作为 int32 推送到计算堆栈上。
IL_0001 从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中
IL_0002 将索引 0 处的局部变量加载到计算堆栈上。
同样。
1 System.Int32 i = new System.Int32();
2 Console.WriteLine(i);
3 Console.ReadKey();
生成的IL也一样。 就不贴了.
所以你可以认为
1 int
2 string
就是语法糖. 其实最后就是生成的一样的代码.
为了方便你编码.
比如还有
1 int i = 0;
2 Int64 l = i;
3 Console.WriteLine(l);
4 Console.ReadKey();
1 int i = 0;
2 Int64 l = (Int64)i;
3 Console.WriteLine(l);
4 Console.ReadKey();
1 .maxstack 1
2 .locals init ([0] int32 i,
3 [1] int64 l)
4 IL_0000: ldc.i4.0
5 IL_0001: stloc.0
6 IL_0002: ldloc.0
7 IL_0003: conv.i8
8 IL_0004: stloc.1
9 IL_0005: ldloc.1
10 IL_0006: call void [mscorlib]System.Console::WriteLine(int64)
11 IL_000b: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
12 IL_0010: pop
13 IL_0011: ret
隐式转换。 不用你再去写什么 (int64)或者 Convert.ToInt64() 之类的.
不过他也有限制。只有在确认不会发生数据丢失的情况下,才允许隐式转换.
比如 从小的转向大的. int32 转 int64
否则
错误 3 无法将类型“long”隐式转换为“int”。存在一个显式转换(是否缺少强制转换?) 45 24 EFTest
本书作者不建议使用这些语法糖。
理由无外物 会让你不清楚 究竟做了什么 ,和其他编程语言标准不一致等等。
我当然完全无视这些.
checked 和 unchecked关键字用来限定检查或者不检查数学运算溢出的
如果使用了checked发生数学运算溢出时会抛出OverflowException
如果使用了unchecked则不会检查溢出,算错了也不会报错。
首先在VS中,Checked 应该是默认打开的
生成就已经报错了.
1 int a = unchecked( int.MaxValue * 2);
a = -2
unchecked 溢出后会生成一个特定的数。 具体算法不清楚. 特定场景比如你就需要一个不重复的数值。 那就可以用他.
对于这两个指令。应用场景实在太小了. 就不深入研究了.
1. 什么是值类型
System.ValueType 派生的都是值类型
2. 什么是引用类型
在文档中查看一个类型时,任何称为“类”的类型都是引用类型
引用类型
内存必须从托管堆上分配堆上分配的每个对象都有一些额外的成员,这些成员必须初始化对象中的其他字节(为字段而设)总是设为零从托管堆上分配一个对象时,可能强制执行一次垃圾收集操作
值类型
值类型的实例一般在线程栈上分配
在代表值类型实例的一个变量中,并不包含一个指向实例的指针。相反,变量中包含了实例本身的字段。
由于变量已经包含了实例的字段,所以为了操作实例中的字段,不再需要提领一个指针。
值类型的实例不受垃圾回收器的控制
书中个的理由是
如果所有类型都是引用类型,应用程序的性能将显著下降。
设想假如每次使用一个Int32值时,都进行一次内存分配,性能会受到多么大的影响!
为了提升简单的、常用的类型的性能,CLR提供了名为“值类型”的轻量级类型
从数据结构来说.
栈就是一个后进先出的简单结构.
堆是一种是经过排序的树形结构.
复杂度不一样. 分配的速度自然也不一样.
栈中的内存通过寄存器定位
堆在寄存器中就一个地址,再通过地址去内存里面找理论上也慢一点儿.
不过在现在这么屌的CPU,还有没有区别就不知道了. 或许已经达到可以忽略的地步了.
关于值类型引用类型的分配.
网上很多是这样说的。
值类型 栈
引用类型中的值类型 GC Heap
引用类型 < 85000byte GC Heap
引用类型 > 85000byte Large Object Heap
值类型 和 引用类型的区别
1 public struct ccc 2 { 3 4 } 5 6 public class bbb : aaa 7 { 8 9 } 10 11 var c1 = new ccc(); 12 var c2 = c1; 13 14 var b1 = new bbb(); 15 var b2 = b1;
查看一下内存地址
c1 0x0679EF28
c2 0x0679EF24
b1 0x021E4AAC
b2 0x021E4AAC
引用类型中的值类型
1 var a = new aaa(); 2 var b = a; 3 4 a.c++; 5 6 Console.WriteLine(a.c); 7 Console.WriteLine(b.c);
结果是 1,1
a 和 b 的内存地址都是 0x02314AAC
至于 是在GC Heap 还是 Large Object Heap
这个我没有想到办法验证.
本书说了一堆注意事项。 其实稍微多用一点儿 自己就明白了.
唯一要注意的是传递。
1 public struct ccc 2 { 3 4 } 5 6 var a = new ccc(); 7 test(a); 8 9 public static void test(ccc i) 10 { 11 12 Console.WriteLine(i.GetType()); 13 }
看内存地址
a 0x0652E860
i 0x0652E850
因为值类型都在线程栈中. 这样的传递都会复制一次.
特别是面向对象结构一层一层的. 如果 传递的值类型过大. 必定会对性能有一定影响.
当然也有特殊的int,地址是一样的.
其实就是值类型和引用类型的相互转换
值类型转引用类型 装箱.
引用类型转值类型你个 拆箱.
我没有找到测试方法。比如他究竟怎么运作的。 从栈怎么复制过去的。
所以就引用书中的说法。
值类型转引用类型。
引用类型转值类型
书中特别提了一句
拆箱其实就是获取一个指针的过程,该指针指向包含在一个对象中的原始值类型(数据字段)
我并不是特别理解这一句话。
如果堆中保留了 原始值类型。 可是他依然在堆中。 所以不管怎么样都需要有一次复制操作。
注意事项
1.如果包含了“对已装箱值类型实例的引用”的变量为null,就抛出一个NullReferenceException异常。
2.如果引用指向的对象不是所期待的值类型的一个已装箱实例,就抛出一个InvalidCastException异常。
1 public static void Main() { 2 Int32 x = 5; 3 Object o = x; 4 //对x进行装箱,o引用已装箱的对象 5 Int16 y = (Int16) o; 6 //抛出一个InvalidCastException异常 7 }
Int32 x = 5; Object o = x; Int64 y = (Int64)o;
拆箱必须和原有的类型一致,不管大小都不行.
标签:
原文地址:http://www.cnblogs.com/HeyTommy/p/4330633.html