1. 程式人生 > 其它 >CLR Via C#: 基元型別、引用型別和值型別

CLR Via C#: 基元型別、引用型別和值型別

程式語言的基元型別 - 編譯器直接支援的資料型別

基元型別直接對映到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);
            }

 

引用型別和值型別

  1. 引用另一篇部落格中的一句話:值型別就是現金,要用直接用;引用型別是存摺,要用還得先去銀行取現。
  2. 值型別的例項一般線上程棧上分配。在代表值型別例項的一個變數中,並不包含一個指向例項的指標。相反,變數中包含了例項本身的欄位。
  3. 在文件中檢視一個型別時,任何稱為“類”的型別都是引用型別,文件將所有值型別都成為結構或列舉
  4. 引用型別,string和class統稱為引用型別,當宣告一個類時,只在棧中分配一小片記憶體用於容納一個地址,而此時並沒有為其分配堆上的記憶體空間。當使用new建立一個類的例項時,分配堆上的空間,並把堆上空間的地址儲存到棧上分配的小空間中。
  5. 兩者的主要區別:
    • 值型別的記憶體空間分配在棧上;而引用型別的記憶體空間分配在堆上
    • 棧的記憶體分配時自動釋放;而堆的記憶體是有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; }