C#中基元类型、引用类型与值类型

本文主要学习有关类型和通用语言运行时(CLR)的一些基础知识。

目录

1、所有类型的基类型:System.Object

CLR要求每个类型最终都继承自System.Object类,所以任何一组对象都有一组方法的最小集合。
下表列出了System.Object类提供的几个公共方法:

公有方法 描述
Equals 如果两个对象具有相同的值
GetHashCode 方法返回对象的值的散列码
ToString 表示对象状态的字符串
GetType 返回该方法所属对象的类型

2、基元类型

编译器直接支持的数据类型是基元类型。
基元类型和.NET框架中的类型有直接的映射关系。在C#中,int直接映射为System.Int32类型。C#中的string是基元类型,直接映射到.NET框架中的String,所以没有任何不同。
隐式转化:如果转化过程时安全的,也就是说在转化过程中数据不会丢失,那么久进行隐式转换。
显示转换:转换过程不安全,意味着可能会丢失精度或者数量级,那就要求显示转换。

3、引用类型与值类型

在使用引用类型的时候,需要由一些性能考虑。首先考虑以下事实:

  • 引用类型的内存必须从托管堆中分配。
  • 每个在托管堆中分配的对象都有一些与之关联的额外附加成员必须被初始化。
  • 从托管堆中分配对象可能会导致执行垃圾回收机制。
    因此,如果代码中的所有数据都是引用类型的话,应用程序的性能会大打折扣。为了提高使用性能,CLR还提供了值类型的数据类型。值类型的实例通常分配在线程的堆栈上,值类型变量本身包含了一个数据。值类型不受垃圾收集器的控制,因此也减少了托管堆的压力,以及应用程序在整个生存周期中需要垃圾回收的次数。
  • 任何被称为类的类型是引用类型;
  • 结构、枚举类型是值类型;
  • 所有的值类型都继承自System.ValueType;
    下面的实例说明了值类型和引用类型的不同:
     class Program
    {
        static void Main(string[] args)
        {
            //引用类型的内存必须从托管堆中分配,new操作符
            //返回的就是托管堆中对象的内存地址
            SomRef r1 = new SomRef();
            //值类型声明时编译器就在堆栈中分配了内存,不受垃圾回收器的控制
            SomVal v1 = new SomVal();
            r1.x = 5;//修改托管堆中对象的内存中的一些关联成员
            v1.x = 5;//直接改变堆栈中数据的值

            Console.WriteLine("r1.x = {0}", r1.x);
            Console.WriteLine("v1.x = {0}", v1.x);

            SomRef r2 = r1;//引用类型对象赋值时只复制对象的引用,而不复制对象本身
            SomVal v2 = v1;//值类型对象赋值时现在对站上分配内存空间,然后直接将实际的数据值复制过去

            r1.x = 8;
            v1.x = 9;
            Console.WriteLine("r1.x = {0}",r1.x);
            Console.WriteLine("v1.x = {0}", v1.x);
            Console.WriteLine("r2.x = {0}", r2.x);
            Console.WriteLine("v2.x = {0}", v2.x);
            Console.ReadKey();
        }
    }
    /// <summary>
    /// 引用类型
    /// </summary>
    class SomRef
    {
        public Int32 x;
    }
    /// <summary>
    /// 值类型
    /// </summary>
    struct SomVal
    {
        public Int32 x;
    }

运行结果如下:
这里写图片描述
上面代码执行的过程如下图所示:
这里写图片描述

在设计自己的类型时,我们需要仔细考虑是将它们定义为值类型还是引用类型。下面是值类型和引用类型的一些区别:

  • 值类型对象有两种表示:装箱和未装箱形式;引用类型总是装箱形式。

  • 值类型都继承自System.ValueType。

  • 值类型都是密封的。
  • 引用类型变量包含着对象在托管堆中的内存地址,默认地,当一个引用类型变量被创建时,它被初始化为null,表示该引用变量目前没有一个有效的对象。值类型变量初始化为0.
  • 当拷贝一个值类型变量时,会将变量的值拷贝过去,但拷贝一个引用类型变量时,只拷贝内存地址。

4、 值类型的装箱与拆箱

值类型没有被分配在托管堆中,不会被执行垃圾收集。
在.NET框架中,将一个值类型转化为引用类型的过程叫做装箱操作。装箱操作通常由一下几步组成:

  1. 从托管堆中为新生成的引用类型对象分配内存。分配的内存大小为,值类型实例的本身大小加上一些额外空间。
  2. 将值类型实例的字段拷贝到托管堆上新分配的内存中。
  3. 返回托管堆中新分配对象的内存地址,该地址是一个指向对象的引用。值类型实例也就变成了一个引用类型对象。

将引用类型转换为值类型的操作为拆箱操作,对一个引用类型的拆箱操作通常由一下几个步骤完成:
1. 如果该引用为null,将会抛出一个NUllReferenceException异常。
2. 如果该引用指向的是一个已装箱的值类型对象,那么返回值类型对象的指针。

猜你喜欢

转载自blog.csdn.net/u014677855/article/details/82111358