摘錄:
線程堆棧和線程堆:都是記憶體地區,實值型別分配在堆棧上【後進先出】;參考型別變數分配在堆棧上,內容分配在堆上;
1.實值型別
a.實值型別包括結構和枚舉,參考型別包括類、介面、委託等。還有一種特殊的實值型別,稱為簡單類型(Simple Type),比如 byte,int等
b.所有的實值型別都隱式地繼承自 System.ValueType類型(注意System.ValueType本身是一個抽象類別),所以不能顯示讓一個實值型別(結構)再繼承另外一個類,因為c#不支援多重繼承,而System.ValueType和所有的參考型別都繼承自 System.Object基類,
c.當聲明一個實值型別的變數(Variable)的時候,變數本身包含了實值型別的全部欄位,該變數會被分配線上程堆棧(Thread Stack)上。
d.編譯器隱式地會為結構類型建立了無參數建構函式。在這個建構函式中會對結構成員進行初始化,所有的實值型別成員被賦予0或相當於0的值(針對Char類型),所有的參考型別被賦予null值。(因此,Struct類型不可以自行聲明無參數的建構函式)。所以,我們可以通過隱式聲明的建構函式去建立一個ValPoint類型變數:
public struct ValPoint
{
public int x;
public ValPoint(int x)
{
this.x = x;
}
}
ValPoint vPoint1 = new ValPoint(); Console.WriteLine(vPoint.x); // 輸出為0 我們將上面代碼第一句的運算式由“=”分隔拆成兩部分來看:
•左邊 ValPoint vPoint1,在堆棧上建立一個ValPoint類型的變數vPoint,結構的所有成員均未賦值。在進行new ValPoint()之前,將vPoint壓到棧上。
•右邊new ValPoint(),new 操作符不會分配記憶體,它僅僅調用ValPoint結構的預設建構函式,根據建構函式去初始化vPoint結構的所有欄位。
注意上面這句,new 操作符不會分配記憶體,僅僅調用ValPoint結構的預設建構函式去初始化vPoint的所有欄位。那如果我這樣做,又如何解釋呢?
Console.WriteLine((new ValPoint()).x); // 正常,輸出為0
//在這種情況下,會建立一個臨時變數,然後使用結構的預設建構函式對此臨時變數進行初始化。
2.引用類型
public class RefPoint
{
public int x;
public RefPoint(int x)
{
this.x = x;
}
public RefPoint() { }
}
當我們僅僅寫下一條聲明語句:
RefPoint rPoint1; //它的效果是僅僅在堆棧上建立一個不包含任何資料,也不指向任何對象(不包含建立在堆上的對象的地址)的變數。
而當我們使用new操作符時:
rPoint1= new RefPoint(1);
會發生這樣的事:
1.在應用程式堆(Heap)上建立一個參考型別(Type)的執行個體(Instance)或者叫對象(Object),並為它分配記憶體位址。
2.自動傳遞該執行個體的引用給建構函式。(正因為如此,你才可以在建構函式中使用this來訪問這個執行個體。)
3.調用該類型的建構函式。
4.返回該執行個體的引用(記憶體位址),賦值給rPoint變數。
/////////////小結值參數、參考型別參數、輸出參數///////////////////////////
1.值參數
資料通過複製實參的值傳給形參,方法被調用時,系統做如下操作:
A.在棧中為形參分配空間
B.複製實參的值到形參,這樣形參中的值的改變不會影響原來實參中的值,只是原來實參值的一份拷貝。
------------實參不一定是變數,它可以是任何能計算成相應資料類型的運算式。
2.引用參數
必須在方法地聲明和調用中都使用ref修飾符,實參必須是變數,在用作實參前必須被賦值,如果是參考型別變數,可以賦值為一個引用或null值
A.不在棧中為形參分配新的記憶體
B.形參的名稱相當於實參變數的別名,跟實參一樣引用相同的記憶體位置。
3.輸出參數
用於從方法體內把資料傳出到調用代碼,它們非常類似於引用參數。
A.必須在聲明的調用中都使用out修飾符
B.實參必須是變數,不能是其他運算式類型
C.不在棧中為形參分配新的記憶體
D.形參的名稱相當於實參變數的別名,跟實參一樣引用相同的記憶體位置。
E.在方法內部,輸出參數在被讀取之前必須被賦值。
F.每個輸出參數在方法返回之前必須被賦值。
4.參數數組
它允許零個或多個實參對應一個特殊的形參。
A.在一個參數列表中只能有一個參數數組
B.如果有,它必須是列表中的最後一個
eg: void ListInts(params int[] inVals) { }