陳翠娥 王學(xué)伶
(1.長(zhǎng)沙民政職業(yè)技術(shù)學(xué)院軟件學(xué)院,湖南 長(zhǎng)沙 410004;2.國(guó)網(wǎng)河北保定供電公司,河北 保定 071051)
C#是一種編程語(yǔ)言,它是為生成在.NET Framework上運(yùn)行的各種應(yīng)用程序而設(shè)計(jì)的。C#語(yǔ)言簡(jiǎn)單、功能強(qiáng)大、類型安全,而且是面向?qū)ο蟮?。C#憑借在許多方面的創(chuàng)新,在保持C語(yǔ)言風(fēng)格的表現(xiàn)力和雅致特征的同時(shí),實(shí)現(xiàn)了應(yīng)用程序的快速開(kāi)發(fā)。C#的屬性(Properties)、特性(Attributes)、反射(Reflection)等功能在學(xué)習(xí)的時(shí)候較難理解。本文探索這幾個(gè)功能及應(yīng)用,以幫助讀者深入理解C#的這幾個(gè)獨(dú)特功能。
屬性是一種成員,它提供靈活的機(jī)制來(lái)讀取、寫(xiě)入或計(jì)算私有字段的值。屬性可用作公共數(shù)據(jù)成員,但它們實(shí)際上是稱為“訪問(wèn)器”的特殊方法。這樣可以輕松訪問(wèn)數(shù)據(jù),還有助于提高方法的安全性和靈活性。
如下所示的代碼段展示了屬性的應(yīng)用:
屬性使用時(shí)要注意幾個(gè)地方:
(1)屬性是允許類公開(kāi)獲取和設(shè)置值的公共方法,而隱藏了實(shí)現(xiàn)或驗(yàn)證代碼。
(2)get屬性訪問(wèn)器用于返回屬性值,而set訪問(wèn)器用于分配新值,這些訪問(wèn)器可以具有不同的訪問(wèn)級(jí)別,如public int Hour{get{return hour;}protected set{hour=value;}}
(3)value關(guān)鍵字用于定義由set訪問(wèn)器分配的值。
(4)不實(shí)現(xiàn)set訪問(wèn)器的屬性均為只讀。
(5)對(duì)于不需要任何自定義訪問(wèn)器代碼的簡(jiǎn)單屬性,請(qǐng)考慮選擇使用自動(dòng)實(shí)現(xiàn)的屬性的選項(xiàng),如public int Hour{get;set;}
元數(shù)據(jù)是有關(guān)在程序中定義的類型的信息。所有的.NET程序集都包含指定的一組元數(shù)據(jù),這些元數(shù)據(jù)描述在程序集中定義的類型和類型成員。
元數(shù)據(jù)用以對(duì)存儲(chǔ)在公共語(yǔ)言運(yùn)行時(shí)可移植可執(zhí)行文件(PE)文件或存儲(chǔ)在內(nèi)存中的程序進(jìn)行描述。將C#代碼編譯為PE文件時(shí),便會(huì)將元數(shù)據(jù)插入到該文件的一部分中,而將代碼轉(zhuǎn)換為Microsoft中間語(yǔ)言(MSIL)并將其插入到該文件的另一部分中。在模塊或程序集中定義和引用的每個(gè)類型和成員都將在元數(shù)據(jù)中進(jìn)行說(shuō)明。當(dāng)執(zhí)行代碼時(shí),運(yùn)行時(shí)將元數(shù)據(jù)加載到內(nèi)存中,并引用它來(lái)發(fā)現(xiàn)有關(guān)代碼的類、成員、繼承等信息。元數(shù)據(jù)以非特定語(yǔ)言的方式描述在代碼中定義的每一類型和成員。通過(guò)MSIL反匯編工具打開(kāi)可執(zhí)行文件,可以查看到完整的元數(shù)據(jù)信息。元數(shù)據(jù)存儲(chǔ)以下信息:
(1)程序集的說(shuō)明
①標(biāo)識(shí)(名稱、版本、區(qū)域性、公鑰)
②導(dǎo)出的類型
③該程序集所依賴的其他程序集
④運(yùn)行所需的安全權(quán)限
(2)類型的說(shuō)明
①名稱、可見(jiàn)性、基類和實(shí)現(xiàn)的接口
②成員(方法、字段、屬性、事件、嵌套的類型)
(3)屬性
修飾類型和成員的其他說(shuō)明性元素
特性和屬性是完全不同的兩種機(jī)制,屬性用作類的成員,而特性是為應(yīng)用程序提供元數(shù)據(jù)信息的一種機(jī)制。特性提供功能強(qiáng)大的方法,用以將元數(shù)據(jù)或聲明信息與代碼(程序集、類型、方法、屬性等)相關(guān)聯(lián)。特性與程序?qū)嶓w關(guān)聯(lián)后,即可在運(yùn)行時(shí)使用名為“反射”的技術(shù)查詢特性。特性有如下特點(diǎn):
(1)特性可向程序中添加元數(shù)據(jù);
(2)可以添加自定義特性,以指定所需的任何附加信息;
(3)可以將一個(gè)或多個(gè)特性應(yīng)用到整個(gè)程序集、模塊或較小的程序元素(如類和方法);
(4)特性可以與方法和屬性相同的方式接受參數(shù);
(5)程序可以使用反射檢查自己的元數(shù)據(jù)或其它程序內(nèi)的元數(shù)據(jù)。
特性可以放置在幾乎所有的聲明中。在C#中,特性的指定方法為:將括在方括號(hào)中的特性名置于其應(yīng)用到的實(shí)體的聲明上方??赏ㄟ^(guò)下列過(guò)程將特性應(yīng)用到代碼元素:
(1)定義新特性,或者通過(guò)從.NET Framework導(dǎo)入特性的命名空間,使用預(yù)定義特性,如Conditional、WebMethod、DllImport、Obsolete等特性;
(2)在緊鄰代碼元素之前放置特性,從而將該特性應(yīng)用于代碼元素;
(3)為特性指定位置參數(shù)和命名參數(shù)。
如上所示的代碼段示例了預(yù)定義屬性O(shè)bsolete的使用方法,上例中第2個(gè)參數(shù)為false,在Main方法中調(diào)用A()將出現(xiàn)警告,如果為true,則會(huì)出現(xiàn)語(yǔ)法錯(cuò)。
下文將通過(guò)“編寫(xiě)代碼實(shí)現(xiàn)添加漏洞修復(fù)報(bào)告”示例來(lái)說(shuō)明自定義特性的應(yīng)用。
如上所示的代碼段聲明了一個(gè)自定義特性類BugFixingAttribute,它必須繼承Attribute類,此例中包括定位參數(shù)(必須)和命名參數(shù)(可選)。
如上所示的代碼段在類和方法上應(yīng)用了自定義特性。編寫(xiě)以下測(cè)試代碼進(jìn)行加法運(yùn)算,程序運(yùn)行后,特性即保存至可執(zhí)行文件中,可以通過(guò)反射查詢。
.Net的應(yīng)用程序由以下幾個(gè)部分組成:程序集(Assembly)、模塊(Module)、類型(class)。反射提供一種編程的方式,讓程序員可以在程序運(yùn)行時(shí)獲得這幾個(gè)組成部分的相關(guān)信息。例如,通過(guò)反射可以在運(yùn)行時(shí)獲得.NET中的每一個(gè)類型(包括類、結(jié)構(gòu)、委托、接口和枚舉等)的成員,包括方法、屬性、事件,以及構(gòu)造函數(shù)等,還可以獲得每個(gè)成員的名稱、限定符和參數(shù)等等??梢允褂梅瓷鋭?dòng)態(tài)創(chuàng)建類型的實(shí)例,將類型綁定到現(xiàn)有對(duì)象,或從現(xiàn)有對(duì)象獲取類型并調(diào)用其方法或訪問(wèn)其字段和屬性。例如,如果獲得了構(gòu)造函數(shù)的信息,即可直接創(chuàng)建對(duì)象,即使這個(gè)對(duì)象的類型在編譯時(shí)還不知道。
實(shí)現(xiàn)反射需要使用到如下類:Assembly、Type、MethodInfo、FieldInfo、EventInfo等,這些類都包含在System.Reflection命名空間下。其中Assembly類可以定義和加載程序集,加載在程序集清單中列出模塊,以及從此程序集中查找類型并創(chuàng)建該類型的實(shí)例。Type類可以獲得對(duì)象的類型信息,此信息包含對(duì)象的所有要素:方法、構(gòu)造器、屬性等等,通過(guò)Type類可以得到這些要素信息,并且調(diào)用之。MethodInfo包含方法的信息,通過(guò)這個(gè)類可以得到方法的名稱、參數(shù)、返回值等,并且可以調(diào)用之。
反射在下列情況下很有用:
(1)當(dāng)需要訪問(wèn)程序元數(shù)據(jù)中的特性時(shí);
(2)檢查和實(shí)例化程序集中的類型;
(3)在運(yùn)行時(shí)構(gòu)建新類型;
(4)執(zhí)行后期綁定,訪問(wèn)在運(yùn)行時(shí)創(chuàng)建的類型的方法。
下面的代碼段通過(guò)反射查看前面例題中的特性,代碼中使用到了Type類及GetCustomAttributes()方法、GetMethods()方法,MethodInfo類。
反射提供了以上文字描述中的功能,但是反射也不是萬(wàn)能的。使用反射時(shí)要注意以下幾點(diǎn):
(1)現(xiàn)實(shí)應(yīng)用程序中很少需要使用反射類型;
(2)使用反射動(dòng)態(tài)綁定需要犧牲性能;
(3)有些元數(shù)據(jù)信息是不能通過(guò)反射獲取的;
(4)某些反射類型是專門(mén)為那些CLR開(kāi)發(fā)編譯器開(kāi)發(fā)的,所以你要意識(shí)到不是所有的反射類型都是適合所有需求的。
本文作者在多年教學(xué)過(guò)程中發(fā)現(xiàn)初學(xué)者對(duì)C#中屬性、特性和反射的理解比較困難,因此撰寫(xiě)本文從實(shí)際應(yīng)用的角度出發(fā)通過(guò)具體示例簡(jiǎn)要地介紹了它們的原理和機(jī)制。
[1]史浩.VS C#泛型、多態(tài)及反射[J].福建電腦,2014,(11).
[2]王毅.淺析C#反射機(jī)制應(yīng)用及效率[J].大科技,2013,(9).
[3]郭慶華,朱戰(zhàn)立.利用C#.Net反射技術(shù)實(shí)現(xiàn)軟件界面動(dòng)態(tài)存儲(chǔ)[J].電腦知識(shí)與技術(shù),2010,(1).