歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C#中值類型和引用類型

C#中值類型和引用類型

日期:2017/3/1 9:33:14   编辑:Linux編程

本文將介紹C#類型系統中的值類型和引用類型,以及兩者之間的一些區別。同時,還會介紹一下裝箱和拆箱操作。

值類型和引用類型

首先,我們看看在C#中哪些類型是值類型,哪些類型是引用類型。

值類型:

  • 基礎數據類型(string類型除外):包括整型、浮點型、十進制型、布爾型。  
    • 整型(sbyte、byte、char、short、ushort、int、uint、long、ulong )
    • 浮點型(float 和 double )
    • 十進制型(decimal )
    • 布爾型(bool )
  • 結構類型(struct)
  • 枚舉類型(enum)

引用類型:

  • class、interface、delegate、object、string、Array

默認值

變量的初始化中,都會有一個默認值,在C#中,我們可以通過default關鍵字去查看某個類型的默認值。

通過default(int)可以看到,int的默認值是0,default(bool)顯示布爾類型的默認值是false。

對於所有的引用類型,默認值都會是null。

注意,這裡有個特殊的情況就是結構struct,如果對一個結構進行default操作,我們將得到每個結構成員的初始值狀態。也就是說,值類型成員賦予值類型的默認值,引用類型成員賦予引用類型的默認值。

簡單對比值類型和引用類型

下面,我們通過一個簡單的例子看看。假設有一個Point類型,有x和y兩個坐標成員。

同樣是下面一段代碼

Point p1 = new Point(5,9);
Point p2 = p1;

如果Point類型是通過結構struct實現,那麼p2將會是p1的一個副本,也就是說任何一個的修改都不會影響另外一個;如果Point類型是通過類class實現,那麼p2和p1的引用值將會指向同一個對象。

為了進一步了解值類型和引用類型,我們需要介紹一下棧和堆這兩個基本概念。

棧和堆

當我們在32位系統上運行一個程序的時候,這個程序就會有一個4GB的進程運行空間。我們所要討論的棧和堆就存放在這個4GB的空間中。

棧和堆的簡介

在C#中,棧(Stack)是指調用棧(call stack);堆(Heap)是指托管堆,由.NET垃圾收集器自動管理。

這裡就不對棧和堆進行詳細的分析了,只是舉一個簡單的例子來大致描述棧和堆的工作原理。

從圖中可以看到,局部變量在棧上的變化(入棧),當函數執行結束後,棧上的空間將會被清理;但是我們在堆上分配的空間始終從在,只能等待GC去幫我們清理不會被引用到的空間。

值類型和引用類型的存放

介紹過棧和堆之後,下面我們看看值類型和引用類型是怎麼存放的。

對於值類型的變量,這個變量本身就代表這個值類型的值;但是,對於引用類型的變量,這個引用類型的實例是在托管堆上分配的空間,而這個變量本身只是代表一個指向托管堆實例的引用(指針)

所以這裡,我們可以對值類型和引用類型變量的存儲有兩個概括:

  • 引用類型永遠存儲在堆裡
  • 值類型和引用(指針)永遠存儲在它們聲明時所在的堆或棧裡
    • 如果一個值類型不是在方法中定義的,而是在一個引用類型裡,那麼此值類型將會被放在這個引用類型裡並存儲在堆上

注意:根據上面第二點概括,可以得到"值類型一定存儲在棧中"這個說法是錯誤的。例如,我們有一個Student類,在這個類中的Age屬性是一個值類型,但是這個值類型是存儲在Student類實例的空間中,也就是在堆上。

class Student
{
    public string Name { get; set; }
    public int Age{ get; set; }
} 

裝箱和拆箱

由於C#中所有的數據類型都是由基類System.Object繼承而來的,所以值類型和引用類型的值可以通過顯式(或隱式)操作相互轉換。

這裡,可以將裝箱和拆箱描述為:

  • 裝箱是將值類型轉換為引用類型
  • 拆箱是將引用類型轉換為值類型

裝箱/拆箱的內部操作

其實,在裝箱和拆箱的過程中都對應一系列的轉換,這裡就通過下圖表示了。

在值類型進行裝箱時,生成的是全新的引用對象,這會有時間損耗,也就是造成效率降低。所以在C# 2.0中就引入了泛型來減少裝箱操作和拆箱操作消耗。

總結

本文介紹了C#中的值類型和引用類型,以及棧和堆的基本概念。然後分析了值類型和引用類型在棧和堆中的存放。

同時,我們也了解到了:

  • 當使用引用類型時,我們是在和指向引用類型的引用(指針)打交道,而不是引用類型本身
  • 當使用值類型時,我們是在和值類型本身打交道

Copyright © Linux教程網 All Rights Reserved