CLR Via C#: 基元型別、引用型別和值型別
阿新 • • 發佈:2022-03-08
程式語言的基元型別 - 編譯器直接支援的資料型別
基元型別直接對映到Framework類庫(FCL)中存在的型別
int a1 = 0; System.Int32 a2 = 0; int a3 = new int(); System.Int32 a4 = new System.Int32();
C#基元型別:
- sbyte
- byte
- short
- ushort
- int
- uint
- long
- ulong
- char
- float
- double
- bool
- decimal
- string
- object
- dynamic
編譯器能執行基元型別之間的隱式或顯示轉換。只有在轉換“安全”的時候,C#允許隱式轉換。所謂“安全”,是指不會發生資料丟失的情況。“不安全”意味著在轉換之後,有可能丟失精度或者數量級。
除了轉型,基本型別還能寫成文字常亮。
Console.WriteLine(123.ToString() + 456.ToString()); //"123456"
checked和unchecked基元型別操作
對基元型別執行的許多算術運算都可能造成溢位。
Byte b = 100; b = (Byte)(b + 200); Console.WriteLine(b); // 44 Console.ReadLine();
讓C#編譯器控制溢位的一個辦法是使用/checked+編譯器開關。這個開關只是編譯器在生成程式碼是,使用加、減、乘和轉換指令的溢位檢測版本。除了全域性性的開啟或關閉溢位檢測,程式設計師還可以在程式碼的指定區域控制溢位檢測。
UInt32 invalid = unchecked((UInt32)(-1)); Console.WriteLine(invalid); Console.ReadLine();
UInt32 invalid = checked((UInt32)(-1)); // OverflowException Console.WriteLine(invalid); Console.ReadLine();
checked { Byte b = 100; b = (Byte)(b + 200); }
引用型別和值型別
- 引用另一篇部落格中的一句話:值型別就是現金,要用直接用;引用型別是存摺,要用還得先去銀行取現。
- 值型別的例項一般線上程棧上分配。在代表值型別例項的一個變數中,並不包含一個指向例項的指標。相反,變數中包含了例項本身的欄位。
- 在文件中檢視一個型別時,任何稱為“類”的型別都是引用型別,文件將所有值型別都成為結構或列舉
- 引用型別,string和class統稱為引用型別,當宣告一個類時,只在棧中分配一小片記憶體用於容納一個地址,而此時並沒有為其分配堆上的記憶體空間。當使用new建立一個類的例項時,分配堆上的空間,並把堆上空間的地址儲存到棧上分配的小空間中。
- 兩者的主要區別:
-
- 值型別的記憶體空間分配在棧上;而引用型別的記憶體空間分配在堆上
- 棧的記憶體分配時自動釋放;而堆的記憶體是有GC(垃圾回收)來釋放
- 值型別存取速度快,引用型別存取速度慢
- 值型別表示實際資料,引用型別表示指向儲存在記憶體堆中的資料的指標或引用
- 值型別繼承自System.ValueType (ValueType是繼承自System.Object的),引用型別繼承自System.Object
- 引用型別的Equals方法預設比較地址,而值型別的預設比較值
- 引用型別可以派生出新的型別,而值型別不能
- 引用型別可以設定為null值,值型別一般不能(只有Nullable<T>可以設定為null值)
- 引用型別變數的賦值只複製對物件的引用,而不復制物件本身。而將一個值型別變數賦給另一個值型別變數時,將複製物件
- 值型別一旦定義,則不可以變
class Program { static void Main(string[] args) { SomeRef r1 = new SomeRef(); //在堆上分配 SomeVal v1 = new SomeVal(); //在棧上分配 r1.x = 5; v1.x = 5; Console.WriteLine(r1.x); Console.WriteLine(v1.x); SomeRef r2 = r1; // 5 SomeVal v2 = v1; // 5 r1.x = 8; v1.x = 9; Console.WriteLine(r1.x); // 8 Console.WriteLine(r2.x); // 5 Console.WriteLine(v1.x); // 9 Console.WriteLine(v2.x); // 5 Console.ReadLine(); } } //引用型別,由於使用了‘class’ class SomeRef { public Int32 x; } //值型別,由於使用了'struct' struct SomeVal { public Int32 x; }