程式設計結構(C#)
正文
值型別和引用型別
值型別派生自System.ValueType,分配在棧上,不能被繼承,變數預設按值傳遞,當它們超出定義的作用域時被回收。
引用型別分配在託管堆上,變數指向例項所佔的記憶體地址,變數預設按引用傳遞(變數的地址傳入被呼叫的函式),託管堆被垃圾回收時變數消亡。
傳值與傳址
按值傳遞值型別,被呼叫者不能改變引數值;按引用傳遞值型別,可以改變引數值。
如果按值傳遞引用型別,被呼叫者可能改變物件的狀態資料的值,但不能改變所引用的物件,即不能讓物件指向另外一個物件。
如果按引用傳遞引用型別,被呼叫者可能改變物件的狀態資料的值和所引用的物件。
引數修飾符out和ref的區別
out: 呼叫方法之前不需要初始化,輸出引數由被呼叫的方法賦值,如果被呼叫的方法沒給輸出引數賦值,會出現編譯錯誤。
ref: 呼叫者賦初值,並且可以由被呼叫方法(可選地)重新賦值。
Internal和protected作用範圍
Internal: 只能在包含它的程式集中訪問該方法
Protected: 只有派生的型別和該類本身能訪問該方法。
Protected internal: 只能在包含它的程式集,和派生類的程式碼中訪問。
Using關鍵字
Using關鍵字用來:確保在物件引用超出作用域時,在實現了IDisposable介面的物件上自動呼叫Dispose()方法,實現資源回收。
靜態建構函式
靜態建構函式適用於初始化在編譯時未知的靜態資料值,例如,需要從外部檔案/資料庫讀取或生成隨機數等。一個類只能定義一個靜態建構函式,靜態建構函式只執行一次,靜態建構函式的執行優先於任何例項級別的建構函式。
垃圾回收
在使用.NET進行託管程式設計時,不需要對託管堆進行直接操作。如果託管堆沒有足夠的記憶體來分配請求的物件,GC就會進行垃圾回收。
重寫Finialize()的唯一原因是,C#類通過PInvoke或COM互操作性使用了非託管資源(如原始的作業系統檔案控制代碼,資料庫連線等)。
Finialize方法是保證垃圾回收時清除非託管資源。但對於資料庫和檔案控制代碼等非常寶貴的資源,應該儘快釋放。除了重寫Finialize()方法之外,可以實現IDisposable介面,它定義的Dispose方法可以由使用者手工呼叫。
物件的代
垃圾回收時,CLR會試圖尋找不可到達的物件,它不會逐個檢查託管堆上的每一個物件。為了優化這個過程,堆上的每一個物件都屬於某個代:
第0代:從沒有標記為回收的新分配的物件
第1代:在上一次垃圾回收中沒有被回收的物件
第2代:在一次以上的垃圾回收後仍然沒有被回收的物件
垃圾回收器檢查和處理所有的第0代物件,如果獲得足夠的空閒記憶體,就不用繼續檢查第1代和第2代的物件,同時沒有被回收的物件被提升到第1代。
GAC
Global Assembly Cache是全域性程式集快取。大多數共享程式集都安裝在這個快取中,其中也安裝了一些私有程式集。如果私有程式集使用本機影象生成器(Ngen.exe)編譯為本機程式碼,也會儲存在這個快取中。
內部影象生成器(native image generator)Ngen.exe,可以在安裝期間把IL程式碼編譯為本機程式碼,這樣程式啟動更快。
正式的處置模式
public class MyResourceWrapper : IDisposable {
private bool disposed = false;
public void Dispose() {
CleanUp(true);
GC.SuppressFinalize(this);//跳過終結
}
private void CleanUp(bool disposing) {
if (!this.disposed) {
if (disposing) {
//釋放託管的資源(在包含的可處置物件上呼叫Dispose)
}
//在這裡釋放非託管的資源
}
disposed = true;
}
~MyResourceWrapper() {
CleanUp(false);
}
}