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