其他分享
首页 > 其他分享> > CLR基础 - 基元类型、值类型和引用类型

CLR基础 - 基元类型、值类型和引用类型

作者:互联网

编程语言的基元类型

  某些数据类型如此常用,以至于许多编辑器允许代码以简化语法来操纵它们。没简化之前的代码如下所示:

System.Int32 a = new System.Int32();

简化之后的代码如下:

int a =0;

编译器直接支持的数据类型称为 基元类型。基元类型直接映射到 Framework 类库( FCL)中存在的类型。表 5-1 列出了FCL 类型在 C# 中有的基元类型。只要符合公共语言规范(CLS)的类型,其他语言都提供了类似的基元类型。

 

checkedunchecked 

C#允许程序员自己决定如何处理溢出。溢出检查默认关闭。如果想让C# 编译器控制溢出的一个办法是使用 /checked+ 编译器开关。这样生成的代码会稍慢一些,因为CLR 会检查这些运算,判断是否发生溢出。如果发生溢出则抛出 OverflowException 异常。

除了全局性的打开和关闭溢出检查,程序员还可以在代码的特定区域控制溢出检查。如下所示使用 了checked 和 unchecked 操作符来提供这种灵活性。

UInt32 invalid = unchecked((UInt32) (-1));

 

引用类型和值类型

引用类型从托管堆中分配,C#的new 操作符返回对象内存地址—— 即指向对象数据的内存地址。使用引用类型注意以下4 点:

 

为提升简单和常用的类型的性能,CLR 提供了名为“值类型”的轻量级类型。值类型的实例一般在线程栈上分配,(注意 也能作为字段嵌入到引用类型的对象中)。

值类型的实例变量中保存的就是实例本身的字段。值类型的实例不受垃圾回收的控制,缓解了托管堆的压力,并减少了应用程序生存期内的垃圾回收次数。

 

 

下面的例子说明值类型在定义时使用 new 和不适用new 的区别。

SomeVal v1; // SomeVal 是值类型,它在栈上分配,并且也会初始化为 0,但是在使用时会提示使用为赋值的字段。
SomeVal v1 = new SomeVal(); //SomeVal 中的字段会被初始化为 0.使用时也不会报错。

 

什么时候该用值类型而不是引用类型呢?

 

值类型的局限性

 

值类型的装箱和拆箱

将值类型转换成引用类型要使用装箱机制,下面是值类型的实例进行装箱时发生的事情,看完后你一定不会让它发生在你的代码中。

拆箱过程的代价要小得多,拆箱实际就是获取指针的过程,将堆中已装箱的对象的各个字段复制到基于栈的值类型实例中。

拆箱过程中常出现的问题,就是拆箱之后值类型原来是 int32 还是 int64,还是其他的什么。

下面是难以觉察到发生装箱的情况。

 

C# 不允许对已经装箱的值类型中的字段进行更改。不过可以用接口欺骗C#。

看下面的列子:

 

 

对象相等性和一致性

Object 的 Equals 方法是像下面这样实现的:

Object 的Equals 方法的默认实现实际是同一性,而非相等性。

下面展示了 Equals 方法应该如何实现。

 

对于同一性检查调用 Object的静态方法 ReferenceEquals,而不能使用 C#的 == 操作符(除非把两个操作数都转为 Object)。ReferenceEquals原型如下:

 

System.ValueType 就重写了 Object 的Equals 方法,并进行了正确的实现来执行值的相等性检查。ValueType 的Equals 内部是这样实现的:

由于 CLR 反射机制慢,定义自己的值类型时应重写 Equals 方法来提供自己的实现,从而提高自己类型的实例进行值相等性比较的性能。自己的实现不调用 base.Equals。

自己实现时要注意:

 

 

 

标签:Object,System,基元,实例,Equals,类型,装箱,CLR
来源: https://www.cnblogs.com/mingjie-c/p/11494104.html