1. 程式人生 > >Value Type And Reference Type

Value Type And Reference Type

值型別和引用型別
在解釋C#資料型別之前、理解C#的兩類資料型別之間的區別很重要
1.值型別(Value types)
2.引用型別(Reference types)

下一部分我們關注值型別和引用型別在句法上的區別,理論上,值型別和引用型別的區別是值型別直接儲存自身的值,引用型別儲存一個自身值的引用,C#中值型別主要是一些基礎型別(如 整形,浮點,非指標(pointers )或引用),在VB或C++中,引用型別是和VB中引用型別,C++中指標型別是一樣的.這些型別在記憶體中時存在不同的地方,值型別儲存在被稱之為棧(stack)的地方,引用型別儲存在被叫做堆(heap)的地方,由於不同的分配的情況下,很好意識一個型別是值型別或是引用型別這點很重要,For example,int 是值型別,
下面的例子的導致結果是在記憶體中有兩個位置儲存值20
// i and j are both of type int
i = 20;
j = i;

然而,考慮到下面的程式碼,在這段程式碼中,假設你已定義一個Vector類,它含有一個int型別的成員Value
Vector x, y;
x = new Vector();
x.Value = 30; // Value is a field defined in Vector class
y = x;
Console.WriteLine(y.Value);
y.Value = 50;
Console.WriteLine(x.Value);

重點是在執行這段程式碼後,這裡只有一個Vector物件,x,y同是指向記憶體(memory )中同一個位置[儲存Vector],因為x,y都是一個引用型別的變數,申明每一個變數就能簡單的儲存一個引用—這就不需要例項化一個已知道型別的物件,這和C++中申明指標或VB中物件引用是一樣的,不論在那種情況一個物件都不會被建立的,但為了建立一個物件,你得使用New關鍵字,如上所示,因為x,y同指向一個物件,改變x會影響到y,反過來也一樣,因此,上斷程式碼會顯示30和50.如果一個變數是一個引用,在它沒有指向任何物件的時候,我們可以設定它值為null:

y=null;

如果一個引用被設定為null,那很清楚的是不可能呼叫任何和它有直接關係非靜態的成員函式或欄位,如果你這樣做執行時丟擲異常,C++中,開發人員可以選擇是否一個給定值被訪問直接或通過一個指標,VB相對比較嚴格,就拿COM物件,它是引用型別,同時簡單型別一直是引用型別,C#在這點和VB是相似的,值型別和引用型別的判斷是由其資料型別判斷的,所以,int, for exampl,一直是值型別,你不可能給int型別賦值一個引用型別,在C#中,基礎資料型別如布林和long型別都是值型別,這意味著如果你定義
一個bool變數,並給它附一個其他bool變數的值,那你會發現在記憶體中,有兩個分開的bool值,過後,你改變原有的bool變數的值,第二個bool的值不會改變,這些型別的賦值只是拷貝自身的值.

相反,C#大多數複雜的資料型別,包含使用者自定義類都是引用型別,他們都分配在堆中,可呼叫,可訪問,有生命週期,公共語言執行時(CLR)的實現一個複雜的演算法來跟蹤該引用變數仍可達,並已被孤立。每隔一段時間(Periodically),CLR將摧毀孤立的物件和返回記憶體中被佔用的資源給作業系統。這是由垃圾收集器來做。C#中已經設計了這種方式,因為高效能最好保持原始型別的服務(如int和布林)值型別和較大的型別,包含許多領域(通常是帶類的情況下)引用型別,如果你想定義自己的型別為值型別,你應該定義它作為一個結構。

下面是個例子:看看它們的區別吧再見

   class A
    {
        public int Num
        {
            get;
            set;
        }

        public override string ToString()
        {
            return "A";
        }
    }


     static void Main(string[] args)
        {
            //Value Type
            int i = 5;
            int j = 0;
            j = i;
            Console.WriteLine("i:{0},j:{1}",i,j);
            j = 9;
            Console.WriteLine("i:{0},j:{1}", i,j);


            //Reference Type
            A a, b;
             a = new A();
            a.Num = 9;
            b = a;
            Console.WriteLine("a.Num:{0},b.Num:{1}", a.Num, b.Num);
            b.Num = 50;
            Console.WriteLine("a.Num:{0},b.Num:{1}", a.Num, b.Num);


            //Reference Type
            string sa, sb;
            sa = "You";
            sb = sa;
            Console.WriteLine("sa.{0},sb.{1}",sa,sb);
            sb = "I";
            Console.WriteLine("sa.{0},sb.{1}", sa, sb);
            Console.ReadKey();


        }