C#中構造函數(shù)和析構函數(shù)用法實例詳解
本文實例講述了C#中構造函數(shù)和析構函數(shù)用法。分享給大家供大家參考,具體如下:
構造函數(shù)與析構函數(shù)是一個類中看似較為簡單的兩類函數(shù),但在實際運用過程中總會出現(xiàn)一些意想不到的運行錯誤。本文將較系統(tǒng)的介紹構造函數(shù)與析構函數(shù)的原理及在C#中的運用,以及在使用過程中需要注意的若干事項。
一.構造函數(shù)與析構函數(shù)的原理
作為比C更先進的語言,C#提供了更好的機制來增強程序的安全性。C#編譯器具有嚴格的類型安全檢查功能,它幾乎能找出程序中所有的語法問題,這的確幫了程序員的大忙。但是程序通過了編譯檢查并不表示錯誤已經(jīng)不存在了,在“錯誤”的大家庭里,“語法錯誤”的地位只能算是冰山一角。級別高的錯誤通常隱藏得很深,不容易發(fā)現(xiàn)。
根據(jù)經(jīng)驗,不少難以察覺的程序錯誤是由于變量沒有被正確初始化或清除造成的,而初始化和清除工作很容易被人遺忘。微軟利用面向對象的概念在設計C#語言時充分考慮了這個問題并很好地予以解決:把對象的初始化工作放在構造函數(shù)中,把清除工作放在析構函數(shù)中。當對象被創(chuàng)建時,構造函數(shù)被自動執(zhí)行。當對象消亡時,析構函數(shù)被自動執(zhí)行。這樣就不用擔心忘記對象的初始化和清除工作。
二.構造函數(shù)在C#中的運用
構造函數(shù)的名字不能隨便起,必須讓編譯器認得出才可以被自動執(zhí)行。它的命名方法既簡單又合理:讓構造函數(shù)與類同名。除了名字外,構造函數(shù)的另一個特別之處是沒有返回值類型,這與返回值類型為void的函數(shù)不同。如果它有返回值類型,那么編譯器將不知所措。在你可以訪問一個類的方法、屬性或任何其它東西之前,第一條執(zhí)行的語句是包含有相應類的構造函數(shù)。甚至你自己不寫一個構造函數(shù),也會有一個缺省構造函數(shù)提供給你。
下面列舉了幾種類型的構造函數(shù)
1)缺省構造函數(shù)
class TestClass { public TestClass(): base() {} }
上面已介紹,它由系統(tǒng)(CLR)提供。
2)實例構造函數(shù)
實例構造函數(shù)是實現(xiàn)對類中實例進行初始化的方法成員。如:
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); // 用構造函數(shù)初始化對象 … } }
聲明了一個類Point,它提供了兩個構造函數(shù)。它們是重載的。一個是沒有參數(shù)的Point構造函數(shù)和一個是有兩個double參數(shù)的Point構造函數(shù)。如果類中沒有提供這些構造函數(shù),那么會CLR會自動提供一個缺省構造函數(shù)的。但一旦類中提供了自定義的構造函數(shù),如Point()和Point (double x, double y),則缺省構造函數(shù)將不會被提供,這一點要注意。
3) 靜態(tài)構造函數(shù)
靜態(tài)構造函數(shù)是實現(xiàn)對一個類進行初始化的方法成員。它一般用于對靜態(tài)數(shù)據(jù)的初始化。靜態(tài)構造函數(shù)不能有參數(shù),不能有修飾符而且不能被調用,當類被加載時,類的靜態(tài)構造函數(shù)自動被調用。如:
using System.Data; class Employee { private static DataSet ds; static Employee() { ds = new DataSet(...); } ... }
聲明了一個有靜態(tài)構造函數(shù)的類Employee。注意靜態(tài)構造函數(shù)只能對靜態(tài)數(shù)據(jù)成員進行初始化,而不能對非靜態(tài)數(shù)據(jù)成員進行初始化。但是,非靜態(tài)構造函數(shù)既可以對靜態(tài)數(shù)據(jù)成員賦值,也可以對非靜態(tài)數(shù)據(jù)成員進行初始化。
如果類僅包含靜態(tài)成員,你可以創(chuàng)建一個private的構造函數(shù):private TestClass() {…},但是private意味著從類的外面不可能訪問該構造函數(shù)。所以,它不能被調用,且沒有對象可以被該類定義實例化。
以上是幾種類型構造函數(shù)的簡單運用,下面將重點介紹一下在類的層次結構中(即繼承結構中)基類和派生類的構造函數(shù)的使用方式。派生類對象的初始化由基類和派生類共同完成:基類的成員由基類的構造函數(shù)初始化,派生類的成員由派生類的構造函數(shù)初始化。
當創(chuàng)建派生類的對象時,系統(tǒng)將會調用基類的構造函數(shù)和派生類的構造函數(shù),構造函數(shù)的執(zhí)行次序是:先執(zhí)行基類的構造函數(shù),再執(zhí)行派生類的構造函數(shù)。如果派生類又有對象成員,則,先執(zhí)行基類的構造函數(shù),再執(zhí)行成員對象類的構造函數(shù),最后執(zhí)行派生類的構造函數(shù)。
至于執(zhí)行基類的什么構造函數(shù),缺省情況下是執(zhí)行基類的無參構造函數(shù),如果要執(zhí)行基類的有參構造函數(shù),則必須在派生類構造函數(shù)的成員初始化表中指出。如:
class A { private int x; public A( ) { x = 0; } public A( int i ) { x = i; } } class B : A { private int y; public B( ) { y = 0; } public B( int i ) { y = i; } public B( int i, int j ):A(i) { y = j; } } B b1 = new B(); //執(zhí)行基類A的構造函數(shù)A(),再執(zhí)行派生類的構造函數(shù)B() B b2 = new B(1); //執(zhí)行基類A的構造函數(shù)A(),再執(zhí)行派生類的構造函數(shù)B(int) B b3 = new B(0,1); //執(zhí)行執(zhí)行基類A的構造函數(shù)A(int) ,再執(zhí)行派生類的構造函數(shù)B(int,int)
在這里構造函數(shù)的執(zhí)行次序是一定要分析清楚的。另外,如果基類A中沒有提供無參構造函數(shù)public A( ) { x = 0; },則在派生類的所有構造函數(shù)成員初始化表中必須指出基類A的有參構造函數(shù)A(i),如下所示:
class A { private int x; public A( int i ) { x = i; } } class B : A { private int y; public B():A(i) { y = 0; } public B(int i):A(i) { y = i; } public B(int i, int j):A(i) { y = j; } }
三.析構函數(shù)和垃圾回收器在C#中的運用
析構函數(shù)是實現(xiàn)銷毀一個類的實例的方法成員。析構函數(shù)不能有參數(shù),不能有任何修飾符而且不能被調用(是系統(tǒng)自動調用)。由于析構函數(shù)的目的與構造函數(shù)的相反,就加前綴‘~'以示區(qū)別。
雖然C#(更確切的說是CLR)提供了一種新的內(nèi)存管理機制---自動內(nèi)存管理機制(Automatic memory management),資源的釋放是可以通過“垃圾回收器” 自動完成的,一般不需要用戶干預,但在有些特殊情況下還是需要用到析構函數(shù)的,如在C#中非托管資源的釋放。
資源的釋放一般是通過"垃圾回收器"自動完成的,但具體來說,仍有些需要注意的地方:
1. 值類型和引用類型的引用其實是不需要什么"垃圾回收器"來釋放內(nèi)存的,因為當它們出了作用域后會自動釋放所占內(nèi)存,因為它們都保存在棧(Stack)中;
2. 只有引用類型的引用所指向的對象實例才保存在堆(Heap)中,而堆因為是一個自由存儲空間,所以它并沒有像"棧"那樣有生存期("棧"的元素彈出后就代表生存期結束,也就代表釋放了內(nèi)存),并且要注意的是,"垃圾回收器"只對這塊區(qū)域起作用;
然而,有些情況下,當需要釋放非托管資源時,就必須通過寫代碼的方式來解決。通常是使用析構函數(shù)釋放非托管資源,將用戶自己編寫的釋放非托管資源的代碼段放在析構函數(shù)中即可。需要注意的是,如果一個類中沒有使用到非托管資源,那么一定不要定義析構函數(shù),這是因為對象執(zhí)行了析構函數(shù),那么"垃圾回收器"在釋放托管資源之前要先調用析構函數(shù),然后第二次才真正釋放托管資源,這樣一來,兩次刪除動作的花銷比一次大多的。下面使用一段代碼來示析構函數(shù)是如何使用的:
public class ResourceHolder { … ~ResourceHolder() { // 這里是清理非托管資源的用戶代碼段 } }
四.小結
構造函數(shù)與析構函數(shù)雖然是一個類中形式上較簡單的函數(shù),但它們的使用決非看上去那么簡單,因此靈活而正確的使用構造函數(shù)與析構函數(shù)能夠幫你更好的理解CLR的內(nèi)存管理機制,以及更好的管理系統(tǒng)中的資源。
注:CLR
CLR(公共語言運行庫)和Java虛擬機一樣也是一個運行時環(huán)境,它負責資源管理(內(nèi)存分配和垃圾收集),并保證應用和底層操作系統(tǒng)之間必要的分離。
為了提高平臺的可靠性,以及為了達到面向事務的電子商務應用所要求的穩(wěn)定性級別,CLR還要負責其他一些任務,比如監(jiān)視程序的運行。按照.NET的說法,在CLR監(jiān)視之下運行的程序屬于“受管理的”(managed)代碼,而不在CLR之下、直接在裸機上運行的應用或者組件屬于“非受管理的” (unmanaged)的代碼。
CLR將監(jiān)視形形色色的常見編程錯誤,許多年來這些錯誤一直是軟件故障的主要根源,其中包括:訪問數(shù)組元素越界,訪問未分配的內(nèi)存空間,由于數(shù)據(jù)體積過大而導致的內(nèi)存溢出,等等。
更多關于C#相關內(nèi)容感興趣的讀者可查看本站專題:《C#程序設計之線程使用技巧總結》、《C#操作Excel技巧總結》、《C#中XML文件操作技巧匯總》、《C#常見控件用法教程》、《WinForm控件用法總結》、《C#數(shù)據(jù)結構與算法教程》、《C#數(shù)組操作技巧總結》及《C#面向對象程序設計入門教程》
希望本文所述對大家C#程序設計有所幫助。
相關文章
C#刪除只讀文件或文件夾(解決File.Delete無法刪除文件)
這篇文章主要介紹了C#刪除只讀文件或文件夾(解決File.Delete無法刪除文件),需要的朋友可以參考下2015-09-09詳談C# 圖片與byte[]之間以及byte[]與string之間的轉換
下面小編就為大家?guī)硪黄斦凜# 圖片與byte[]之間以及byte[]與string之間的轉換。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02C#實現(xiàn)將數(shù)組內(nèi)元素打亂順序的方法
這篇文章主要介紹了C#實現(xiàn)將數(shù)組內(nèi)元素打亂順序的方法,涉及C#數(shù)組遍歷及隨機數(shù)操作的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08