摘 要:構造函數與析構函數是一個類中看似較為簡單的兩類函數,但在實際運用過程中總會出現一些意想不到的運行錯誤。本文將較系統的介紹構造函數與析構函數的原理及在C#中的運用,以及在使用過程中需要注意的若干事項。
關鍵字:構造函數;析構函數;垃圾回收器;非托管資源;托管資源
一.構造函數與析構函數的原理
作為比C更先進的語言,C#提供了更好的機制來增強程序的安全性。C#編譯器具有嚴格的類型安全檢查功能,它幾乎能找出程序中所有的語法問題,這的確幫了程序員的大忙。但是程序通過了編譯檢查並不表示錯誤已經不存在了,在“錯誤”的大家庭裡,“語法錯誤”的地位只能算是冰山一角。級別高的錯誤通常隱藏得很深,不容易發現。
根據經驗,不少難以察覺的程序錯誤是由於變量沒有被正確初始化或清除造成的,而初始化和清除工作很容易被人遺忘。微軟利用面向對象的概念在設計C#語言時充分考慮了這個問題並很好地予以解決:把對象的初始化工作放在構造函數中,把清除工作放在析構函數中。當對象被創建時,構造函數被自動執行。當對象消亡時,析構函數被自動執行。這樣就不用擔心忘記對象的初始化和清除工作。
二.構造函數在C#中的運用
構造函數的名字不能隨便起,必須讓編譯器認得出才可以被自動執行。它的命名方法既簡單又合理:讓構造函數與類同名。除了名字外,構造函數的另一個特別之處是沒有返回值類型,這與返回值類型為void的函數不同。如果它有返回值類型,那麼編譯器將不知所措。在你可以訪問一個類的方法、屬性或任何其它東西之前, 第一條執行的語句是包含有相應類的構造函數。甚至你自己不寫一個構造函數,也會有一個缺省構造函數提供給你。
class TestClass { public TestClass(): base() {} // 由CLR提供 } 下面列舉了幾種類型的構造函數 1)缺省構造函數 class TestClass { public TestClass(): base() {} }
上面已介紹,它由系統(CLR)提供。
2)實例構造函數
實例構造函數是實現對類中實例進行初始化的方法成員。如:
using System; class Point { public double x, y; public Point() { this.x = 0; this.y = 0; } public Point(double x, double y) { this.x = x; this.y = y; } … } class Test { static void Main() { Point a = new Point(); Point b = new Point(3, 4); // 用構造函數初始化對象 … } }
聲明了一個類Point,它提供了兩個構造函數。它們是重載的。一個是沒有參數的Point構造函數和一個是有兩個double參數的Point構造函數。如果類中沒有提供這些構造函數,那麼會CLR會自動提供一個缺省構造函數的。但一旦類中提供了自定義的構造函數,如Point()和Point(double x, double y),則缺省構造函數將不會被提供,這一點要注意。
3) 靜態構造函數
靜態構造函數是實現對一個類進行初始化的方法成員。它一般用於對靜態數據的初始化。靜態構造函數不能有參數,不能有修飾符而且不能被調用,當類被加載時,類的靜態構造函數自動被調用。如:
using System.Data; class Employee { private static DataSet ds; static Employee() { ds = new DataSet(...); } ... }
聲明了一個有靜態構造函數的類Employee。注意靜態構造函數只能對靜態數據成員進行初始化,而不能對非靜態數據成員進行初始化。但是,非靜態構造函數既可以對靜態數據成員賦值,也可以對非靜態數據成員進行初始化。
如果類僅包含靜態成員,你可以創建一個private的構造函數:private TestClass() {…},但是private意味著從類的外面不可能訪問該構造函數。所以,它不能被調用,且沒有對象可以被該類定義實例化。