C# 變數型別區分

  • 2161
  • 0
  • 2017-10-15

這篇文章主要會簡單探討這三種變數型別如何分類:Primitive Type (基礎型別)Reference Type(參考型別)Value Type(資料型別)。但不會提及使用的差異性。若有錯誤,請多多指教。

 

首先,先簡單介紹一下別名這檔事,以便接下來的說明:

在 C# 的世界中,某些型態有以下左側(C# Built-In Type)與右側(.NET Framework Type)兩種表示法,但其實代表的意義一模一樣,寫哪個都可以。差別只在於左側的是定義在 C# 中;右側的是定義在 .NET Framewrok 中,編譯後都會轉為一樣的東西。所以接下來的介紹,我就不再拘泥使用哪個表示法,明白左右是同樣的意思就好。

object           System.Object
string           System.String
bool             System.Boolean
byte             System.Byte
sbyte            System.SByte
short            System.Int16
ushort           System.UInt16
int              System.Int32
uint             System.UInt32
long             System.Int64
ulong            System.UInt64
float            System.Single
double           System.Double
decimal          System.Decimal
char             System.Char

但雖然左右都是相同的,但在 C# 的規格書-ECMA-334 p.18 中,還是推薦左側這種比較精簡的寫法:

Each of the predefined types is shorthand for a system-provided type. For example, the keyword int refers to the struct System.Int32. As a matter of style, use of the keyword is favoured over use of the complete system type name.

接下來,就進入正題。先說明一下三種型別的分類關係大概如下:

  • Primitive Type (基礎型別)
  • Non-Primitive Type (非基礎型別)
    ---------------------------------------------------
  • Value Type (資料型別)
  • Reference Type(參考型別)

咦?什麼?你說上面跑出第四種型別嗎?沒錯,為了方便說明,我把 Non-Primitive Type (非基礎型別)直接就列上了。看上面的條列方式,約略可以明白我想表達的意思:資料型別可以用兩種方式來分類,就如同人類可以用男、女來分類,也可以用魔法師、麻瓜(不會魔法的)來分類。

 

那先來談談 Primitive 與 Non-Primitive 。

Primitive Type

基礎型別的分類,講白了就是直接被定義在 .NET Framework 之中的。使用 Type.IsPrimitive 可以直接查詢是否為 Primitive Type。也就是以下這些型態: Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, Single。Primitive Type 就這樣,就只是定義而已,講完了。

 string 不在 Primitive Type 當中喔!

Non-Primitive Type

沒錯,非 Primitive Type 的就是 Non-Primitive Type 啦~也講完了!

在寫 C# 時,不記得它是不是 Primitive Type 其實好像也不是很重要,關鍵的 Value Type 與 Reference Type 有搞懂比較要緊。

 

重頭戲來了,談談 Reference Type 與 Value Type。

Value Type

  • struct
  • enum
  • 最上頭提到左邊的 C# Built-In Type 中,除了 object 與 string 之外,其他都是 Value Type,也就是這些: bool、byte、sbyte、char、decimal、double、float、int、uint、long、ulong、short、ushort
DateTime 、IntPtr 也是 struct ,所以都是 Value Type 喔!

Reference Type

非 Value Type 即 Reference Type,就這樣。也就是以下這些:

  • class
  • interface
  • delegate
  • dynamic
  • object
  • string
其中,string 的行為被特別設計過,改得很像 Value Type,特別注意。
有看到一篇文章提到,Value Type 是存放在 stack 的,有 1MB 的大小限制,但因為 string 太大了,無法存放在 stack 中,必須放在 heap,所以才被設計為 reference type。這說法挺有趣的,但 stack 可能也會很大,不知道用超過 1 MB 會發生什麼事?改天再來實驗實驗。

 

結語

  1. 所以 Primitive Type 與 Value Type、Reference Type 根本就不是同一檔事,不要再問「xxx 是屬於 Primitive Type 還是 Reference Type?」了,這問題本身就怪怪的,就像是問說「妙麗是女生還是魔法師?」一樣奇妙。
  2. 從上頭的整理可以看到,C# 的世界中,Primitive Type 一定是 Value Type,但 Value Type 不見得是 Primitive Type(DateTime 就是個反例)。 
  3. 變數型態的大小寫與 Value Type 、Reference Type 毫無關係。例如:int、string、System.Int32、String、...。