C#類和結(jié)構(gòu)詳解
類和結(jié)構(gòu)實(shí)際上都是創(chuàng)建對象(實(shí)例)的模版,每個對象都包含數(shù)據(jù),并提供了處理和訪問數(shù)據(jù)的方法。
類定義了類的每個對象可以包含什么數(shù)據(jù)和功能。
class PhoneCus { public const string DaySend = "Mon"; public int CusId; }
結(jié)構(gòu)與類的區(qū)別是它們在內(nèi)存中的存儲方式,訪問方式和它們的一些特性(稍后詳細(xì)介紹它們的區(qū)別)。
較小的數(shù)據(jù)類型使用結(jié)構(gòu)可提高性能,在語法上,比較類似,主要區(qū)別是使用關(guān)鍵字struct代替class來聲明結(jié)構(gòu)。
struct PhoneCusStruct { public const string DaySend = "Mon"; public int CusId=; }
對于類和結(jié)構(gòu),都是用new來聲明實(shí)例:這個關(guān)鍵字創(chuàng)建對象并對其進(jìn)行初始化。
PhoneCus myCus = new PhoneCus(); PhoneCusStruct myCus2 = new PhoneCusStruct();
上面的例子,類和結(jié)構(gòu)的字段值都默認(rèn)0.
一.類
類中的數(shù)據(jù)和函數(shù)稱為類的成員(數(shù)據(jù)成員和函數(shù)成員)。
1.數(shù)據(jù)成員
數(shù)據(jù)成員是包含類的數(shù)據(jù)————字段,常量和事件的成員。數(shù)據(jù)成員可以是靜態(tài)數(shù)據(jù)。類成員總是實(shí)例成員,除非用static顯示聲明。
2.函數(shù)成員
函數(shù)成員提供了操作類中數(shù)據(jù)的某些功能,包括方法,屬性,構(gòu)造函數(shù),終結(jié)器,運(yùn)算符以及索引。
(1)方法
*C#區(qū)分函數(shù)和方法。C#中函數(shù)包含上述提到的。
*給方法傳遞參數(shù)
參數(shù)可以通過引用或值傳遞給方法。在變量通過引用傳遞給方法時,被調(diào)用的方法得到的就是這個變量,準(zhǔn)確的説就是指向內(nèi)存中變量的指針。所以在方法內(nèi)對變量進(jìn)行的任何改變在方法退出后仍然有效。
而如果變量通過值傳遞給方法,被調(diào)用的方法得到的是變量的一個相同副本,也就是說,在方法退出后,對變量的修改會丟失。
對于復(fù)雜的數(shù)據(jù)類型,按引用傳遞的效率更高,因?yàn)樵诎粗祩鬟f時,必須復(fù)制大量的數(shù)據(jù)。
注意字符串的行為方式有所不同,因?yàn)樽址遣豢勺兊模宰址疅o法采用一般引用類型的行為方式。在方法調(diào)用中,對字符串所做的改變都不會影響原始字符串。
*ref參數(shù)
像上面所説,值類型通過值傳遞變量是默認(rèn)的。但也可以迫使值參數(shù)通過引用傳遞給方法。為此要使用ref關(guān)鍵字。這樣該方法對變量所做的任何改變都會影響原始值。
static void SomeFunction(int[] ints,ref int i) { ints[0] = 100; i = 100; }
在調(diào)用該方法的時候,必須添加ref關(guān)鍵字。
SomeFunction(ints, ref i);
*out參數(shù)
C#要求變量在被引用前必須用一個初始值進(jìn)行初始化。但使用out關(guān)鍵字來初始化可以簡化C# 編譯器所堅(jiān)持的輸入?yún)?shù)的初始化。
在方法的輸入?yún)?shù)前加上out前綴時,傳遞給該方法的變量可以不初始化。而且該變量通過引用傳遞,所以在從被調(diào)用的方法中返回時,對應(yīng)方法對該變量進(jìn)行的任何改變都會保留下來。
在調(diào)用該方法時,仍需要使用out關(guān)鍵字:
static void SomeFunction(int[] ints,out int i) { ints[0] = 100; i = 100; } SomeFunction(ints, out i);
*命名參數(shù)
參數(shù)一般需要按定義的順序傳遞給方法。命名參數(shù)允許按任意順序傳遞。
string FullName(string firstName,string lastName) { renturn firstName+" " +lastName; }
調(diào)用方法:
FullName("John","Doe"); FullName(lastName:"Doe",firstName:"John");
*可選參數(shù)
參數(shù)也可以是可選的。必須為可選參數(shù)提供默認(rèn)值??蛇x參數(shù)還必須是方法定義的最后一個參數(shù)。
void TestMethod(int notOption,int option = 10) { Console.WriteLine( notOption + option); }
*方法的重載
C#支持方法的重載————方法的幾個版本有不同的簽名(方法名相同,但參數(shù)的個數(shù)和/或類型不同)。
class MathTest { public int Value; public int GetSquare() { return Value*Value; } public int GetSquare(int x) { return x*x; } }
重載方法在參數(shù)方面的一些限制:
兩個方法不能僅在返回類型上有區(qū)別;
兩個方法不能僅根據(jù)參數(shù)是聲明為ref還是out來區(qū)分。
在任何語言中,對于方法重載,如果調(diào)用了錯誤的重載方法,就有可能出現(xiàn)運(yùn)行錯誤。(后面討論如何避免這些錯誤)。
(2)屬性(property)
屬性是一個方法或一對方法,在客戶端看來,它是一個字段。
public string SomeProperty { get { return "value"; } set { //設(shè)置屬性值 } }
get訪問器不帶任何參數(shù),且必須返回屬性聲明的類型。也不應(yīng)為set訪問器指定任何顯示參數(shù),編譯器會
假定它帶一個參數(shù),器類型也許屬性相同,并表示為value.
private int age public int Age { get { return age; } set { age = valeu; } }
注意所用的命名約定,采用C#的區(qū)分大小寫模式,使用相同的名稱,但公有屬性采用大寫形式命名,如果存在一個等價的私有字段,則采用小寫形式命名。
一些開發(fā)人員喜歡使用把下劃線作為前綴的字段名,如_age,這會為識別字段提供極大的便利。
*只讀和只寫屬性
在屬性定義中省略set訪問器,就會創(chuàng)建只讀屬性。這樣客戶端代碼只可以讀取該屬性的值,但不能設(shè)置值。
private int age public int Age { get { return age; } }
同樣在屬性定義中省略get訪問器,就會創(chuàng)建只寫屬性。
*屬性的訪問修飾符
C#允許給屬性的gei和set訪問器設(shè)置不同的訪問修飾符,所以屬性可以有公有的get訪問器和受保護(hù)的set訪問器。
在gey和set訪問器中,必須有一個具有屬性的訪問級別(公有)。
*自動實(shí)現(xiàn)的屬性
如果屬性的set和get訪問器中沒有任何邏輯,就可以使用自動實(shí)現(xiàn)的屬性。這種屬性會自動實(shí)現(xiàn)后背成員變量。
public int Age { get; set; }
不需要聲明private int age;,編譯器會自動創(chuàng)建它。
使用自動實(shí)現(xiàn)的屬性,就不能在屬性設(shè)置中驗(yàn)證屬性的有效性。但必須有兩個訪問器,不能把屬性設(shè)置為只讀或只寫。
public int Age { get;//報(bào)錯 } 但是,每個訪問器的訪問級別可以不同, public int Age { get; private set; }
(3)構(gòu)造函數(shù)
聲明基本構(gòu)造函數(shù)就是聲明一個與包含的類同名的方法,但該方法沒有返回值。
public class MyClass { public MyClass() { } // }
一般情況下,如果沒有提供任何構(gòu)造函數(shù),編譯器會在后臺創(chuàng)建一個默認(rèn)的構(gòu)造函數(shù)。這是一個基本的構(gòu)造函數(shù),它只能把所有的成員字段初始化為標(biāo)準(zhǔn)的默認(rèn)值。這通常就足夠了,否則需要編寫自己的構(gòu)造函數(shù)。
構(gòu)造函數(shù)的重載與其它方法的規(guī)則相同??梢詾闃?gòu)造函數(shù)提供任意多的的重載,只要它們的簽名有明顯區(qū)別。
public class MyClass { public MyClass() { } public MyClass(int i ) { / / } // }
如果提供了帶參數(shù)的構(gòu)造函數(shù),編譯器就不會自動提供默認(rèn)的構(gòu)造函數(shù)。只有在沒有定義任何構(gòu)造函數(shù)的時候,編譯器才會自動提供默認(rèn)的構(gòu)造函數(shù)。
public class MyNum { private int number; public MyNum(int number) { this.number =number; } }
一般使用this關(guān)鍵字區(qū)分成員字段和同名的參數(shù)。
如果試圖使用無參數(shù)的構(gòu)造函數(shù)實(shí)例化對象就會報(bào)錯:
MyNum num = new MyNum();//報(bào)錯
可以把構(gòu)造函數(shù)定義為private或protected,這樣不相關(guān)的類就不能訪問它們:
public class MyNum { private int number; private MyNum(int number) { this.number =number; } }
上述例子沒有為MyNum定義為任何公有或受保護(hù)的構(gòu)造函數(shù)。這就使MyNum不能使用new運(yùn)算符在外部代碼中實(shí)例化,但可以在MyNum類中編寫一個公有靜態(tài)屬性或方法,以實(shí)例化該類。
這在下面兩種情況下受有用的:
類僅用作某些靜態(tài)成員或?qū)傩缘娜萜?,因此永遠(yuǎn)不會實(shí)例化它。
希望類僅通過某個靜態(tài)成員函數(shù)來實(shí)例化。
*靜態(tài)構(gòu)造函數(shù)
C#可以給類編寫無參數(shù)的靜態(tài)構(gòu)造函數(shù)。這種構(gòu)造函數(shù)只執(zhí)行一次,而前面的構(gòu)造函數(shù)是實(shí)例構(gòu)造函數(shù),只要創(chuàng)建類的對象,就會
執(zhí)行它。
class MyClass { static MyClass() { } }
編寫靜態(tài)構(gòu)造函數(shù)的一個原因是,類有一些靜態(tài)字段或?qū)傩裕枰诘谝淮问褂妙愔?,從外部源中初始化這些靜態(tài)字段和屬性。
.NET運(yùn)行庫不能確保什么時候執(zhí)行靜態(tài)構(gòu)造函數(shù),所以不能把要求在某個特定時刻執(zhí)行的代碼放在靜態(tài)構(gòu)造函數(shù)中。也不能預(yù)計(jì)不同類的靜態(tài)構(gòu)造函數(shù)按照什么順序執(zhí)行。但是可以確保靜態(tài)構(gòu)造函數(shù)最多運(yùn)行一次,就在代碼引用類之前調(diào)用它。
在C#中,通常在第一次調(diào)用類的任何成員之前執(zhí)行靜態(tài)構(gòu)造函數(shù)。
注意,靜態(tài)構(gòu)造函數(shù)沒有訪問修飾符,其它C#代碼從來不調(diào)用它,但在加載類時,總是由.NET運(yùn)行庫調(diào)用它,所以像public,private這樣的訪問修飾符就沒有任何意義。出于同樣原因,靜態(tài)構(gòu)造函數(shù)不能帶任何參數(shù),一個類也只能有一個靜態(tài)構(gòu)造函數(shù)。很顯然,靜態(tài)構(gòu)造只能訪問累的靜態(tài)成員,不能訪問類的實(shí)例成員。
無參數(shù)的實(shí)例構(gòu)造函數(shù)與靜態(tài)構(gòu)造函數(shù)可以在同一個類中同時定義。雖然參數(shù)列表相同,但這并不矛盾,因?yàn)樵诩虞d類的時候執(zhí)行靜態(tài)構(gòu)造函數(shù),在創(chuàng)建實(shí)例時執(zhí)行實(shí)例構(gòu)造函數(shù),所以何時執(zhí)行哪個構(gòu)造函數(shù)不會有沖突。
如果任何靜態(tài)字段有默認(rèn)值,就在調(diào)用靜態(tài)構(gòu)造函數(shù)之前指定它們。
下面演示靜態(tài)構(gòu)造函數(shù)的用法:
class MainEntryPoint { static void Main() { Console.WriteLine("UserPreference:BackColor is " + UserPreference.BackColor.ToString()); } } class UserPreference { public static readonly Color BackColor; static UserPreference() { BackColor = Color.Red; } private UserPreference() { } }
該靜態(tài)變量在靜態(tài)構(gòu)造函數(shù)中進(jìn)行初始化。
*從構(gòu)造函數(shù)中調(diào)用其它構(gòu)造函數(shù)
有時,在一個類中有幾個構(gòu)造函數(shù),這些構(gòu)造函數(shù)包含一些共同的代碼。
class Car { private string des; private int nWheels; public Car(string des,int nWheels) { this.des = des; this.nWheels = nWheels; } public Car(string des) { this.des = des; this.nWheels = 4; } }
這兩個構(gòu)造函數(shù)初始化了相同的字段,顯然最好把所有的代碼放在一個地方。C#有一個特殊的語法,稱為構(gòu)造函數(shù)初始化器,可以實(shí)現(xiàn)這個目的。
class Car { private string des; private int nWheels; public Car(string des,int nWheels) { this.des = des; this.nWheels = nWheels; } public Car(string des):this(des,4) { } }
這里,this關(guān)鍵字僅調(diào)用參數(shù)最匹配的那個構(gòu)造函數(shù)。構(gòu)造函數(shù)初始化器在構(gòu)造函數(shù)的函數(shù)體之前執(zhí)行。
C#構(gòu)造函數(shù)初始化器可以包含對同一個類的另一個構(gòu)造函數(shù)的調(diào)用,也可以包含對直接基類的構(gòu)造函數(shù)的調(diào)用,使用同樣的語法,但應(yīng)用base關(guān)鍵字代替this.初始化器中不能有多個調(diào)用。
3.只讀字段
常量是一個包含不能修改的值的變量。但常量不必滿足所有的要求。有時需要一些一些變量,其值不應(yīng)改變,但在運(yùn)行之前其值是未知的。C#為這種情形提供了另一種類型的變量:只讀字段(readonly)。
readonly關(guān)鍵字比const靈活得多,允許把一個字段設(shè)置為常量,但可以執(zhí)行一些計(jì)算,以確定它得初始值。
其規(guī)則是可以在構(gòu)造函數(shù)中給只讀字段賦值,但不能在其它地方賦值。只讀字段還可以是一個實(shí)例字段,類的每個實(shí)例可以有不同得值。
與const不同,如果要把只讀字段設(shè)置為靜態(tài),就必須顯示得聲明它。
二.匿名類型
var關(guān)鍵字用于表示隱式類型化得變量。var和new關(guān)鍵字一起使用時,可以創(chuàng)建匿名類型。
匿名類型只是一個繼承自O(shè)bject且沒有名稱的類。
var caption = new {FirstName = "John",LastName="Doe"};
這會生成一個包含F(xiàn)irstName,LastName屬性的對象。
創(chuàng)建另一個對象:
var doctor = new {FirstName = "James",LastName="Mc"};
caption和doctor的類型就相同,可以設(shè)置caption = doctor
如果設(shè)置的值來自于另一個對象,就可以簡化初始化器。
var doctor = new {caption.FirstName,caption.LastName};
這些對象的類型名未知。編譯器為類型“偽造”了一個名稱,但只有編譯器才能使用它。
三.結(jié)構(gòu)(struct)
如果僅需要一個小的數(shù)據(jù)結(jié)構(gòu),此時類提供的功能多余我們需要的功能,由于性能原因,最好使用結(jié)構(gòu)。
結(jié)構(gòu)是值類型,它們存儲在棧中或存儲為內(nèi)聯(lián)(inline)(如果它們是存儲在堆中的另一個對象的一部分),其生存期的限制與簡單的數(shù)據(jù)類型一樣。
- *結(jié)構(gòu)不支持繼承。
- *對于結(jié)構(gòu),構(gòu)造函數(shù)的方式與類有一些區(qū)別。編譯器總是提供一個無參數(shù)的默認(rèn)構(gòu)造函數(shù),它是不允許替換的。
- *使用結(jié)構(gòu)可以指定字段如何在內(nèi)存中布局(后面詳細(xì)介紹)
結(jié)構(gòu)實(shí)際上是把數(shù)據(jù)項(xiàng)組合在一起,有時大多數(shù)字段都聲明為public。嚴(yán)格來說,這與編寫.net代碼的規(guī)則相反(字段應(yīng)總是私有的(除const字段外),并由公有屬性封裝)。但是,對于簡單的結(jié)構(gòu),公有字段是可以接受的編程方式。
四.類和結(jié)構(gòu)的區(qū)別
1.結(jié)構(gòu)是值類型
雖然結(jié)構(gòu)是值類型,但在語法上可以把它當(dāng)作類來處理。
struct PhoneCusStruct { public const string DaySend = "Mon"; public int CusId=0; } PhoneCusStruct phoneCusStruct = new PhoneCusStruct(); phoneCusStruct.CusId=3;
因?yàn)榻Y(jié)構(gòu)是值類型,所以new運(yùn)算符與類和其它引用類型的工作方式不同。new運(yùn)算符并不分配堆中的內(nèi)存,而只是調(diào)用相應(yīng)的構(gòu)造函數(shù),根據(jù)傳送給它的參數(shù),初始化所有的字段。
對于結(jié)構(gòu)編寫下面的代碼是合法的:
PhoneCusStruct phoneCusStruct; phoneCusStruct.CusId=3;
結(jié)構(gòu)遵循其它數(shù)據(jù)類型都遵循的規(guī)則:在使用前所有的元素都必須進(jìn)行初始化。在結(jié)構(gòu)上調(diào)用new運(yùn)算符,或者給所有的字段分別賦值,結(jié)構(gòu)就完全初始化了。
如果結(jié)構(gòu)定義為類的成員字段,在初始化包含的對象時,該結(jié)構(gòu)會自動初始化為0.
結(jié)構(gòu)是會影響性能的值類型,但根據(jù)使用結(jié)構(gòu)的方式,這種影響可能是正面的,也可能是負(fù)面的。正面的影響是為結(jié)構(gòu)分配內(nèi)存時,速度很快,因?yàn)樗鼈儗?nèi)聯(lián)或保存在棧中。在結(jié)構(gòu)超出了作用域被刪除時,速度也很快,不需要等待垃圾回收。負(fù)面影響是,只要把結(jié)構(gòu)作為參數(shù)來傳遞或者把一個結(jié)構(gòu)賦予另一個結(jié)構(gòu),結(jié)構(gòu)的內(nèi)容就會被復(fù)制,而對于類只復(fù)制引用。這樣就會有性能損失,根據(jù)結(jié)構(gòu)的大小,性能損失也不同。
注意,結(jié)構(gòu)主要用于小的數(shù)據(jù)結(jié)構(gòu)。當(dāng)把結(jié)構(gòu)作為參數(shù)傳遞給方法時,應(yīng)把它作為ref參數(shù)傳遞,以避免性能損失(這樣只傳遞了結(jié)構(gòu)在內(nèi)存中的地址)。
2.結(jié)構(gòu)和繼承
結(jié)構(gòu)不能從一個結(jié)構(gòu)中繼承。唯一的例外是對應(yīng)的結(jié)構(gòu)(和其它類型一樣)最終派生于類System.Object。因此結(jié)構(gòu)也可以訪問Object的方法。
在結(jié)構(gòu)中也可以重寫Object中的方法——如ToString()方法。
結(jié)構(gòu)的繼承鏈?zhǔn)牵好總€結(jié)構(gòu)派生于System.ValueType類,System.ValueType類有派生于System.Object。ValueType并沒有給Object添加任何成員,但提供了一些更適合結(jié)構(gòu)的實(shí)現(xiàn)方法。
注意,不能為結(jié)構(gòu)提供其它基類。
3.結(jié)構(gòu)的構(gòu)造函數(shù)
為結(jié)構(gòu)定義構(gòu)造函數(shù)的方式與類的方式相同,但不允許定義無參數(shù)的構(gòu)造函數(shù)。因?yàn)樵谝恍┖币姷那闆r下,.NET運(yùn)行庫不能調(diào)用用戶提供的自定義無參數(shù)構(gòu)造函數(shù),因此Microsoft干脆采用禁止在C#的結(jié)構(gòu)內(nèi)使用無參數(shù)的構(gòu)造函數(shù)。
默認(rèn)構(gòu)造函數(shù)會隱式的把字段初始化,即使提供了其它帶參數(shù)的構(gòu)造函數(shù),也會先調(diào)用它。提供字段的初始值也不能繞過默認(rèn)構(gòu)造函數(shù)。下面代碼會編譯錯誤:
struct PhoneCusStruct { public int CusId =0; }
如果PhoneCusStruct聲明為一個類,就不會報(bào)錯了。
另外,可以像類那樣為結(jié)構(gòu)提供Close()或Dispose()方法。
五.弱引用
在應(yīng)用程序代碼內(nèi)實(shí)例化一個類或結(jié)構(gòu)時,只要有代碼引用這個對象,就會形成強(qiáng)引用。這意味著垃圾回收器不會清理這個對象使用的內(nèi)存,一般而言這是好事,因?yàn)榭赡苄枰眠@個對象,但是如果這個對象很大,而且不經(jīng)常訪問。這個時候可以創(chuàng)建對象的弱引用。
弱引用允許創(chuàng)建和使用對象,但在垃圾回收器運(yùn)行時,就會回收對象并釋放內(nèi)存。由于存在潛在的Bug和性能問題,一般不會這么做,但在特定情況下使用是合理的。
弱引用使用WeakReference類創(chuàng)建。因?yàn)閷ο罂赡茉谌我鈺r刻被回收,所以引用該對象前必須確認(rèn)它的存在?! ?/p>
class MainEntryPoint { static void Main() { // Instantiate a weak reference to MathTest object WeakReference mathReference = new WeakReference(new MathTest()); MathTest math; if(mathReference.IsAlive) { math = mathReference.Target as MathTest; math.Value = 30; Console.WriteLine( "Value field of math variable contains " + math.Value); Console.WriteLine("Square of 30 is " + math.GetSquare()); } else { Console.WriteLine("Reference is not available."); } GC.Collect(); if(mathReference.IsAlive) { math = mathReference.Target as MathTest; } else { Console.WriteLine("Reference is not available."); } } } // Define a class named MathTest on which we will call a method class MathTest { public int Value; public int GetSquare() { return Value*Value; } public static int GetSquareOf(int x) { return x*x; } public static double GetPi() { return 3.14159; } }
六.部分類
partial關(guān)鍵字允許把類,結(jié)構(gòu),接口放在多個文件中。
partial關(guān)鍵字的用法:把partial放在class,struct,interface前面即可。
如果聲明類時使用了下面的關(guān)鍵字,這些關(guān)鍵字就必須應(yīng)用于同一個類的所有部分:
public,private,protected,internal,abstract,sealed,new,一般約束
在把部分類編譯后,類的成員和繼承等會合并。
七.靜態(tài)類
如果類只包含靜態(tài)的方法和屬性,該類就是靜態(tài)的。靜態(tài)類在功能上與使用私有靜態(tài)構(gòu)造函數(shù)創(chuàng)建的類相同。都不能創(chuàng)建靜態(tài)類的實(shí)例。
使用static關(guān)鍵字,編譯器可以檢查用戶是否給該類添加了實(shí)例成員。如果是,就會生成一個編譯錯誤。這可以確保不創(chuàng)建靜態(tài)類的實(shí)例。
static class PhoneCusStruct { public static void GetPhene() { } }
調(diào)用:PhoneCusStruct.GetPhene();
八.Object類
前面提到,所有的.NET類都派生自System.Object類.實(shí)際上,如果在定義類的時候沒有指定基類,編譯器就會自動假定這個類派生自O(shè)bject類。其實(shí)際意義在于,除了自己定義的方法和屬性等外,還可以訪問Object定義的許多公有的和受保護(hù)的成員方法。這些方法可用于自己定義的其它類中。
System.Object的方法:
- 1.GetHashCode():如果對象放在名為映射(散列表或字典)的數(shù)據(jù)結(jié)構(gòu)中,就可以使用這個方法。處理這些結(jié)構(gòu)的類使用該方法可以確定把對象放在結(jié)構(gòu)的什么地方。如果希望把類用作字典的一個鍵,就需要重寫這個方法。(后面介紹字典時會詳細(xì)介紹)
- 2.Equals()和ReferenceEquals()方法:后面會詳細(xì)介紹。
- 3.Finalize()方法:在引用對象作為垃圾被回收以清理資源時調(diào)用它。Object中實(shí)現(xiàn)的Finalize()方法實(shí)際上什么也沒有做,因而被垃圾回收器忽略。如果對象擁有對未托管資源的引用,則在該對象被刪除時,就需要刪除這些引用,此時一般要重寫Finalize()方法。垃圾收集器不能直接刪除這些未托管資源的引用,因?yàn)樗回?fù)責(zé)托管的資源,于是它只能依賴用戶提供的Finalize()方法。垃圾收集器不能直接刪除這些未托管資源的引用,因?yàn)樗回?fù)責(zé)托管的資源,于是它只能依賴用戶提供的Finalize方法。
- 4.GetType()方法:這個方法返回從System.Type派生的類的一個實(shí)例。這個對象可以提供對象成員所屬類的很多信息。System.Type還提供了.NET的反射技術(shù)的入口。
- 5.MemberwiseClose()方法:這個方法復(fù)制對象,并返回對副本的一個引用(對于值類型,就是一個裝箱的引用)。得到的副本是一個淺表復(fù)制,即它復(fù)制了類中的所有值類型。如果類包含內(nèi)嵌的引用,就只復(fù)制引用,而不復(fù)制引用的對象。這個方法是受保護(hù)的,所以不能用于復(fù)制外部的對象(可以復(fù)制父類的對象)。該方法不是虛方法,所以不能重寫。
- 6.ToString()方法:是獲取對象的字符串表示的一種快捷方式。當(dāng)只需要快速獲取對象的內(nèi)容,以進(jìn)行調(diào)試時,就可以使用這個方法。在數(shù)據(jù)的格式化方面,它幾乎沒有提供選擇,比如:在原則上日期可以表示為許多不同格式,但DateTime.ToString()沒有在這方面提供任何選擇。這個方法是虛方法,可以重寫這個方法以返回這些類型的正確字符串表示。
九.擴(kuò)展方法
如果有類的源碼,繼承就可以給對象添加方法。但如果沒有源代碼,則可以使用擴(kuò)展方法,它允許改變一個類,但不需要該類的源代碼。
擴(kuò)展方法是靜態(tài)方法,它是類的一部分,但實(shí)際上沒有放在類的源代碼中。假定PhoneCusStruct類需要一個Add()方法,但不能修改源代碼,就可以創(chuàng)建一個靜態(tài)類,把Add()方法添加為一個靜態(tài)方法:
public static class PhoneExtension { public static void Add(this PhoneCusStruct phoneCusStruct,string phone) { // } }
注意擴(kuò)展方法的第一個參數(shù)是要擴(kuò)展的類型,它放在this關(guān)鍵字的后面。這告訴編譯器,這個方法是PhoneCusStruct類型的一部分。在這個例子中,PhoneCusStruct是要擴(kuò)展的類型。在擴(kuò)展方法中,可以訪問所擴(kuò)展類型的所有公有方法和屬性。
調(diào)用:
PhoneCusStruct p =new PhoneCusStruct(); p.Add();//即使方法是靜態(tài)方法,也需要使用實(shí)例方法的語法。
如果擴(kuò)展方法與類中的某個方法同名,就不會調(diào)用擴(kuò)展方法。類中已有的任何實(shí)例方法優(yōu)先。
到此這篇關(guān)于C#類和結(jié)構(gòu)的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#實(shí)現(xiàn)動態(tài)圖標(biāo)閃爍顯示的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)動態(tài)圖標(biāo)閃爍顯示的功能,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以了解一下2022-12-12c#實(shí)現(xiàn)51單片機(jī)頻率計(jì)的代碼分享(數(shù)字頻率計(jì)設(shè)計(jì))
c#實(shí)現(xiàn)51單片機(jī)頻率計(jì)的代碼分享,大家參考使用吧2013-12-12C#創(chuàng)建windows系統(tǒng)用戶的方法
這篇文章主要介紹了C#創(chuàng)建windows系統(tǒng)用戶的方法,涉及C#操作用戶名、密碼、顯示名稱、描述、是否強(qiáng)制修改密碼、密碼是否過期等技巧,非常具有實(shí)用價值,需要的朋友可以參考下2015-04-04C#如何將List<string>轉(zhuǎn)換為List<double>
這篇文章主要介紹了C#如何將List<string>轉(zhuǎn)換為List<double>問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07C# DataTable與Model互轉(zhuǎn)的示例代碼
這篇文章主要介紹了C#DataTable與Model互轉(zhuǎn)的示例代碼,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2020-12-12Winform+.Net6實(shí)現(xiàn)圖片拖拽上傳功能
這篇文章主要為大家詳細(xì)介紹了如何使用WinformPictureBox控件+.Net6 WebApi實(shí)現(xiàn)圖片拖拽上傳功能,文中的示例代碼講解詳細(xì),感興趣的可以學(xué)習(xí)一下2023-09-09C#實(shí)現(xiàn)繪制鼠標(biāo)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)繪制鼠標(biāo)的效果,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下2022-12-12c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼
c#中利用委托反射將DataTable轉(zhuǎn)換為實(shí)體集的代碼,需要的朋友可以參考下2012-10-10