1. 程式人生 > >值型別與引用型別淺析

值型別與引用型別淺析

1、 總概括:

       值型別就是現金,要用直接用;引用型別是存摺,要用還得先去銀行取現。

2、值型別與引用型別簡介

(1)C#的所有值型別均派生自System.ValueType:

           結構體:

               數值型別:整型(byte、short、int、long、char等)、浮點型(float、double)、decimal型(decimal)

               bool型

               使用者定義的結構體

           列舉:enum

           可空型別(System.Nullable<T>泛型結構體) 例如:int? a

總結:值型別(ValueType),值型別例項通常分配線上程的堆疊(stack)上,並且不包含任何指向例項資料的指標,因為變數本身就包含了其例項資料

(2)C#有以下一些引用型別:

           陣列(派生於System.Array)

           使用者用定義的以下型別:類(派生於System.Object)、介面、委託(派生於System.Delegate)

           object(System.Object的別名);

           字串:string(System.String的別名)

String是比較特殊的引用型別:每次建立一個string時,都會重新再託管堆上重新分配新的記憶體空間,所以進行賦值操作的時候,原string的值不變。(可以比較stringBuilder與string)

       String的缺點是每次字串變數的內容發生了改變時,都必須重新分配記憶體。StringBuilder通過分配一個快取,新增,刪除,移除,插入和替換字元等等。執行完之後,將呼叫ToString方法把工作區中的內容轉換為一個字串,方便賦給一個字串變數。這樣StringBuilder會提升一些效能。

(3)相同點與不同點:

       引用型別可以派生出新的型別,而值型別不能;

       引用型別變數的賦值只複製對物件的引用,而不復制物件本身。而將一個值型別變數賦給另一個值型別變數時,將複製包含的值;

3、資料在記憶體中分配位置取決與該變數的資料型別,值型別分配線上程的堆疊上,引用型別則分配在託管堆上,由GC控制回收。

下面是個經典的例子:

private static class ReferenceVsValue
    {
        //引用型別(class關鍵字)
        private class SomeRef { public Int32 x; }
        //值型別(struct關鍵字)
        private struct SomeVal { public Int32 x; }

        public static void Go()
        {
            SomeRef r1 = new SomeRef();   //在堆上分配
            SomeVal v1 = new SomeVal();   // 在棧上分配 
            r1.x = 5;                     // 提領指標
            v1.x = 5;                     // 在棧修改 
            Console.WriteLine(r1.x);      // 顯示”5”
            Console.WriteLine(v1.x);      //同樣顯示”5”  
            // 下圖左半部分反映了執行以上程式碼之後的情形
            SomeRef r2 = r1;              //只複製引用(指標) 
            SomeVal v2 = v1;              // 在棧上分配並且複製成員 
            r1.x = 8;                     // r1.x和r2.x都會更改
            v1.x = 9;                     // 只是更改v1.x,不會更改v2.x 
            Console.WriteLine(r1.x);      // 顯示 "8" 
            Console.WriteLine(r2.x);      // 顯示 "8" 
            Console.WriteLine(v1.x);      // 顯示 "9" 
            Console.WriteLine(v2.x);      // 顯示 "5"  
            //右半部分反映了在執行所有程式碼之後的情況 
        }
    }