一、用var定義變量 在C#3.0中提供了一種新的聲明變量的方式,這就是var。通過這個(gè)關(guān)鍵字,在聲明變量時(shí)就無需指定類型了,變量類型是在初始化時(shí)由編譯器確定的。代碼如下: var ss = "abcd"; MessageBox.Show(ss.GetType().ToString()); 上 面的代碼將顯示System.String,從而證明C#編譯器已經(jīng)將ss編譯成了String變量了。而在輸出ss后,再輸入“.”后,會(huì)看到將 String類型變量的相應(yīng)方法和屬性也列出來了,因此可以斷定,C#將ss看成了String類型,而不是Object。所以使用var定義變量同時(shí)可 以擁有Object和強(qiáng)類型的優(yōu)點(diǎn)。 不過大家不要將var看成是javascript的var,它們的區(qū)別是,javascript是弱類型的語言,而且javascript中的變量(也包括用var聲明的變量)可以變換類型,如下面的javascript所示: var s = "abcd"; s=3; alert(s); 上面的代碼第一次給s賦了一個(gè)字符串,而第二行代碼又給賦了一個(gè)整數(shù)。這樣的代碼在javascript中沒有任何問題。但在C#3.0中,var變量一但被初始化,確定類型后,就無法改變類型了。如下面的代碼是無法編譯通過的: var ss = "abcd"; ss = 44; 綜上所述,在使用var定義變量時(shí)有以下四個(gè)特點(diǎn): 1. 必須在定義時(shí)初始化。也就是必須是var s = “abcd”形式,而不能是如下形式: var s; s = “abcd”; 2. 一但初始化完成,就不能再給變量賦與初始化值類型不同的值了。 3. var要求是局部變量。 4. 使 用var定義變量和object不同,它在效率上和使用強(qiáng)類型方式定義變量完全一樣。但筆者建議如果事先知道變量的類型,盡量使用強(qiáng)類型方式來聲明變量。 否則,就會(huì)造成由于大量使用var,而使得開發(fā)人員很難斷定某個(gè)變量是什么類型。這樣不利于程序的維護(hù)和升級(jí)。 雖然var有利有弊,但筆者個(gè)人認(rèn)為,如果將動(dòng)態(tài)語言轉(zhuǎn)換成C#語言,可以考慮使用var來定義變量。這是因?yàn)閯?dòng)態(tài)語言沒有類型,而要將其轉(zhuǎn)換成強(qiáng)類型的 C#語言,就必須給變量指定個(gè)類型,但事先確定類型是很費(fèi)勁的,不如將其指定成var,再由C#編譯器去確定變量的具體類型。那么如果在轉(zhuǎn)換的過程中,發(fā) 現(xiàn)動(dòng)態(tài)語言的變量改變了類型,該怎么辦呢?這個(gè)可以使用第三部分要講的“匿名類”來解決這個(gè)問題。 二、初始化 如果一個(gè)類有public字段,在建立類的對(duì)象實(shí)例時(shí)可以使用下面的代碼來初始化這些字段; public class MyClass { public String field1; public int field2; public bool field3; } MyClass my = new MyClass(); my.field1 = “abcd”; my.field2 = 44; my.field3 = true; 在C#3.0中提供了一種更簡便的方法來初始化這些public變量,代碼如下: MyClass my = new MyClass { field1 = “abcd”, field2 = 44; field3 =true; }; 上面的代碼的寫法有些象帶參數(shù)的構(gòu)造方法,但這將不是調(diào)用了MyClass的構(gòu)造方法(因?yàn)镸yClass并沒有帶三個(gè)參數(shù)的構(gòu)造方法),而只是C#編譯 器玩的一個(gè)魔術(shù)。實(shí)際上,上面的代碼在編譯后,仍然和使用傳統(tǒng)的初始化字段的方法一樣。只是在語法上看起來更簡單(至少不用寫那么多個(gè)my)。要注意的 的,使用這種方法初始化,必須是public的字段(不能是protected、private或默認(rèn)修飾符的字段)。 在C#3.0中還改進(jìn)了對(duì)集合類的初始化方式(使其初始化的方式類似于數(shù)組)。但遺憾的是,這種初始化方式只支持用泛型的集合類,也就是說,只有實(shí)現(xiàn)了 System.Collections.Generic.違規(guī)廣告ection<T>的集合類才可以使用這種初始化方法。代碼如下: List<string> myList = new List<string> { "data1", "data2", "data3" }; foreach (string data in myList) { textBox1.AppendText(data); } 三、匿名類 在C#3.0中提供了一種新的建立類的方法,代碼如下: var my = new { field1 = "abcd", field2 = 12 }; MessageBox.Show(my.field1); C#編譯器會(huì)自動(dòng)推斷my是一個(gè)有兩個(gè)public字段的類的對(duì)象實(shí)例。也就是說相當(dāng)于下面的代碼: public class MyClass { public String field1; public int field2; } var my = new MyClass(); my.field1 = "abcd"; my.field2 = 25; MessageBox.Show(my.field1); 在第一部分講到如果動(dòng)態(tài)語言在給變量賦值的過程中改變了變量類型,如果將其轉(zhuǎn)換為強(qiáng)類型語言。當(dāng)然,一種方法是將變量聲明成object類型,或是使用匿名類來解決這個(gè)問題。代碼如下: var myVar = new { field_string = “abcd” field_int = 12; }; 然后根據(jù)當(dāng)前這個(gè)變量所使用的類型來決定該使用哪個(gè)類字段。 四、擴(kuò)展方法 這個(gè)世界上總是存在著很多奇妙的東西。然而,在這部分所介紹的擴(kuò)展方法就是其中之一。從字面上看可能讀者很難猜透“擴(kuò)展方法”是什么意思。然而,看了下面的例子,就會(huì)感覺到非常的奇妙。 namespace ExtMethod { public class Class1 { public String s = "bill"; } public class Class2 : Class1 { } public static class AnyClassName { public static String getName(this Class1 class1) { return class1.s + class1.s; } } public partial class Form1 : Form { private void button1_Click(object sender, EventArgs e) { Class1 c = new Class1(); MessageBox.Show(c.getName()); Class2 c = new Class2(); MessageBox.Show(c.getName()); } } } 看到上面的代碼,也許很多人會(huì)感到奇怪,在Class1和Class2中并沒有g(shù)etName方法,怎么在調(diào)用時(shí)出來個(gè)getName方法呢?實(shí)際上,這 就是擴(kuò)展方法的用法,從本質(zhì)上說,擴(kuò)展方法就是將靜態(tài)方法(必須聲明成static)插入到某個(gè)類和其子類中(也就是說,在這些類中可以使用在外部定義的 靜態(tài)方法)。那么要往哪個(gè)類中插入呢?這就要在定義靜態(tài)方法時(shí)指定了。大家可以看看getName方法的第一個(gè)參數(shù),使用了this關(guān)鍵字,這就表明這個(gè) 方法是一個(gè)擴(kuò)展方法,后面的類型就是要插入該方法的類,在本例中是Class1,也就是說在Class1及其子類中都可以使用getName方法。上面的 調(diào)用代碼也相當(dāng)于下面的代碼: Class2 c = new Class2(); MessageBox.Show(AnyClassName.getName(c)); 但使用c.getName可能會(huì)更好一些,而且也降低了對(duì)靜態(tài)方法所在的類(AnyClassName)的依賴性。 在使用擴(kuò)展方法時(shí)應(yīng)注意以下幾點(diǎn): 1. 擴(kuò)展方法所在的類名可以是任意合法的類名。 2. 擴(kuò)展方法所在的類必須和使用擴(kuò)展方法的代碼在同一個(gè)命名空間里,否則無法編譯通過。 3. 在 本例中,Class1和Class2只能聲明成public,因?yàn)锳nyClassName被聲明為public。如果AnyClassName不加修飾 符,Class1和Class2也可以不加修飾符,當(dāng)然,也可以被聲明為public。也就是說,Class1和Class2必須有比 AnyClassName具有更強(qiáng)的訪問性。如下面代碼所示: class Class1 { public String s = "bill"; } class Class2 : Class1 { } static class AnyClassName // 這時(shí)如果前面加public是無法編譯通過的。 { public static String getName(this Class1 class1) { return class1.s + class1.s; } } 4. 如果在Class1或Class2中已經(jīng)有g(shù)etName方法了,那么Class1或Class2中的getName優(yōu)先級(jí)更高。也就是說,擴(kuò)展方法是無法覆蓋原類中的同名(參數(shù)名和類型也相同)的方法的。 擴(kuò)展方法尤其在很多類需要同樣的方法,而這些類又無法繼承其它類時(shí)特別有用。當(dāng)然,在要對(duì)某個(gè)類進(jìn)行擴(kuò)展,但我們并沒有源代碼時(shí),擴(kuò)展方法也可以派上用場。 |
|