本文主要介绍讲述CLR via C#中关于类型的一些知识包括以下内容:基本类型、引用类型和值类型、值类型的装箱与拆箱。 1.基元类型 编译器能够直接支持的数据类型叫做基元类型。例如int, string等。基元类型和.NET框架类库FCL存在着直接的映射关系。 string和String? 面试的时候曾经被问到过这个问题,C#中的基元类型string实际上对应了System.String(FCL)类型,所以两者使用的时候没有什么不同。 类型转换 编译器能够在基元类型之间进行显式或隐式转换。如果转换是安全的,也就是转换过程不会造成数据丢失,则可以直接采用隐式转换。如果是不安全的,则必须采用显式转换。
2. 引用类型和值类型 引用类型和值类型的区别:
结构体直接继承自System.ValueType;而枚举直接继承自System.Enum, Enum类又直接继承自System.ValueType。 下面通过例子看一下他们的区别: 首先定义类和结构体:
看看下图的内存分配情况,就一目了然了。 3. 值类型的装箱与拆箱 ①装箱过程? 装箱:将值类型转换为引用类型。当我们把值类型参数传递给需要引用类型参数的方法时,会自动进行装箱操作。过程如下: 从托管堆为要生成的引用类型分配大小。大小为:值类型实例本身的大小+额外空间(方法表指针和SyncBlockIndex)。 将值类型字段拷贝到刚刚分配的内存中。 返回托管堆中新分配内存的地址。也就是指向对象的引用。 ②拆箱过程? 拆箱:获取指向对象中包含的值类型部分的指针。一般拆箱之后会进行字段拷贝操作,两个操作加起来才是真正与装箱互反的操作。过程如下: 如果引用为Null,则抛出NullReferenceException异常。 如果引用对象不是一个期望值类型的已装箱对象,会抛出InvalidCastException异常。 返回一个指向包含在已装箱对象中值类型部分的指针。 ③实例 拆箱的转型结果必须是它原来未装箱时的类型。
修正:Int16 z=(Int16)(Int32)o;//拆箱成功 这段代码进行了几次装箱?
上面的代码进行了3次装箱,最后一行中v被装箱为引用类型,o首先被拆箱然后再装箱为引用类型。 我们看一下它的IL代码: 字符串连接实际上调用的是Concat方法,该方法的参数要求是object,因此各参数都要转换成object类型。 优化: Console.WriteLine(v.ToString()+”,”+o);//装箱0次 我们要尽量少的进行值类型的装箱拆箱操作,以提高程序性能。 |
|
来自: kittywei > 《111.38-c#类》