Share via


實值和參考型別 (Visual C# Express)

更新:2007 年 11 月

與您熟悉的某些程式設計語言不同的是,C# 有兩種資料型別:實值和參考。如果應用程式的效能很重要,或是如果您對 C# 如何管理資料和記憶體有興趣,了解兩者之間的差別就很重要。

當變數是以基本內建資料型別其中之一,或使用者定義的結構進行宣告時,此變數便是實值型別 (Value Type)。有一個例外是 string 資料型別,它屬於參考型別。

實值型別會將內容儲存在配置於堆疊的記憶體中。例如,在這個案例中,值 42 會儲存在稱為堆疊的記憶體區域中:

int x = 42;

當變數 x 因為所定義的方法完成執行而超出範圍時,堆疊就會捨棄此值。

使用堆疊很有效率,但是實值型別有限的存留期,使其較不適合在不同類別之間共用資料。

相反地,參考型別 (例如類別或陣列的執行個體) 會配置在稱為堆積 (Heap) 的不同記憶體區域中。在下列範例中,組成陣列的十個整數所需要的空間會配置在堆積中。

int[] numbers = new int[10];

當方法完成時,這段記憶體不會歸還給堆積,只有當 C# 的記憶體回收系統判定不再需要它時才會回收。在宣告參考型別時需要較大的額外負荷,但是它們有可以從其他類別存取的優點。

Boxing 與 Unboxing

Boxing 是指定給將實值型別轉換為參考型別的處理序名稱。當您 box 某個變數時,就會建立指向堆積中新複本的參考變數。參考變數是一個物件,因此可以使用每個物件繼承的所有方法。例如,ToString()。這就是以下程式碼的內容:

int i = 67;                              // i is a value type
object o = i;                            // i is boxed
System.Console.WriteLine(i.ToString());  // i is boxed

當您使用設計為配合物件使用的類別時,便會遇到 unboxing:例如,使用 ArrayList 儲存整數。將整數存入 ArrayList 中時,就會被 box 為物件。而從 ArrayList 中讀取時,物件會被 unbox 為整數。

System.Collections.ArrayList list = 
    new System.Collections.ArrayList();  // list is a reference type
int n = 67;                              // n is a value type
list.Add(n);                             // n is boxed
n = (int)list[0];                        // list[0] is unboxed

效能問題

讓我們再深入一點探討。當資料傳遞至方法當做實值型別參數時,就會在堆疊上建立每個參數的複本。很明顯地,如果參數是一個大型資料型別,例如使用許多項目之使用者定義結構,或是執行許多次的方法,這可能會對效能造成影響。

在上述情況中,建議使用 ref 關鍵字將參考傳遞到型別。這是將變數指標傳遞給函式的 C++ 技術,在 C# 的對等用法。當使用 C++ 版本時,方法能夠變更變數的內容,這個動作不是永遠都安全。程式設計人員需要在安全性和效能之間權衡得失。

int AddTen(int number)  // parameter is passed by value
{
    return number + 10;
}
void AddTen(ref int number)  // parameter is passed by reference
{
    number += 10;
}

out 關鍵字類似 ref 關鍵字,但是會告訴編譯器方法必須指派一個值給參數,否則會發生編譯錯誤。

void SetToTen(out int number)
{
    // If this line is not present, the code will not compile.
    number = 10;
}

請參閱

概念

C# 語言入門

內建資料型別 (Visual C# Express)

陣列和集合 (Visual C# Express)

參考

實值型別 (C# 參考)

參考型別 (C# 參考)

Boxing 和 Unboxing (C# 程式設計手冊)