整理cnet0高級編程第5版反射_第1頁
整理cnet0高級編程第5版反射_第2頁
整理cnet0高級編程第5版反射_第3頁
整理cnet0高級編程第5版反射_第4頁
整理cnet0高級編程第5版反射_第5頁
已閱讀5頁,還剩19頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、精品文檔第章反射是一個普通術(shù)語,描述了在運(yùn)行過程中檢查和處理程序元素的功能。例如,反射 允許完成以下任務(wù):枚舉類型的成員實(shí)例化新對象執(zhí)行對象的成員查找類型的信息查找程序集的信息檢查應(yīng)用于類型的定制特性創(chuàng)建和編譯新程序集這個列表列出了許多功能,包括.NET Framework類庫提供的一些最強(qiáng)大、最復(fù)雜的功能。但本章不可能介紹反射的所有功能,僅討論最常用的功能。首先討論定制特性,定制特性允許把定制的元數(shù)據(jù)與程序元素關(guān)聯(lián)起來。這些元數(shù)據(jù) 是在編譯過程中創(chuàng)建的,并嵌入到程序集中。接著就可以在運(yùn)行期間使用反射的一些功能 檢查這些元數(shù)據(jù)了。在介紹了定制特性后,本章將探討支持反射的一些基類,包括Syste

2、m.Type和System.Reflection.Assembly類,它們可以訪問反射提供的許多功能。為了演示定制特性和反射,我們將開發(fā)一個示例,說明公司如何定期升級軟件,自動 解釋升級的信息。在這個示例中,要定義幾個定制特性,表示程序元素最后修改或創(chuàng)建的 日期,以及發(fā)生了什么變化。然后使用反射開發(fā)一個應(yīng)用程序,在程序集中查找這些特性,自動顯示軟件自某個給定日期以來升級的所有信息。本章要討論的另一個示例是一個應(yīng)用程序,該程序讀寫數(shù)據(jù)庫,并使用定制特性,把 類和特性標(biāo)記為對應(yīng)的數(shù)據(jù)庫表和列。然后在運(yùn)行期間從程序集中讀取這些特性,使程序 可以自動從數(shù)據(jù)庫的相應(yīng)位置檢索或?qū)懭霐?shù)據(jù),無需為每個表或列編

3、寫特定的邏輯。12.1 定制特性前面介紹了如何在程序的各個數(shù)據(jù)項(xiàng)上定義特性。這些特性都是Microsoft定義好的,作為.NET Framework類庫的一部分,許多特性都得到了C#編譯器的支持。對于這些特性,編譯器可以以特殊的方式定制編譯過程,例如,可以根據(jù)StructLayout特性中的信息在內(nèi)存中布置結(jié)構(gòu)。.NET Framework也允許用戶定義自己的特性。顯然,這些特性不會影響編譯過程,因 為編譯器不能識別它們,但這些特性在應(yīng)用于程序元素時(shí),可以在編譯好的程序集中用作 元數(shù)據(jù)。這些元數(shù)據(jù)在文檔說明中非常有用。但是,使定制特性非常強(qiáng)大的因素是使用反射, 代碼可以讀取這些元數(shù)據(jù),使用它們

4、在運(yùn)行期間作出決策,也就是說,定制特性可以直接 影響代碼運(yùn)行的方式。例如,定制特性可以用于支持對定制許可類進(jìn)行聲明代碼訪問安全 檢查,把信息與程序元素關(guān)聯(lián)起來,由測試工具使用,或者在開發(fā)可擴(kuò)展的架構(gòu)時(shí),允許 加載插件或模塊。12.1.1 編寫定制特性為了理解編寫定制特性的方式,應(yīng)了解一下在編譯器遇到代碼中某個應(yīng)用了定制特性 的元素時(shí),該如何處理。以數(shù)據(jù)庫為例,假定有一個C#屬性聲明,如下所示。FieldName(SocialSecurityNumber)public string SocialSecurityNumberget / etc.當(dāng)C#編譯器發(fā)現(xiàn)這個屬性有一個特性FieldName時(shí)

5、,首先會把字符串 Attribute添加到這個名稱的后面,形成一個組合名稱FieldNameAttribute,然后在其搜索路徑的所有命名空間(即在using語句中提及的命名空間)中搜索有指定名稱的類。但要注意,如果用一個特性 標(biāo)記數(shù)據(jù)項(xiàng),而該特性的名稱以字符串Attribute結(jié)尾,編譯器就不會把該字符串加到組合名稱中,而是不修改該特性名。因此,上面的代碼實(shí)際上等價(jià)于:FieldNameAttribute(SocialSecurityNumber) public string SocialSecurityNumberget / etc.編譯器會找到含有該名稱的類,且這個類直接或間接派生自Sy

6、stem.Attribute。編譯器還認(rèn)為這個類包含控制特性用法的信息。特別是屬性類需要指定:特性可以應(yīng)用到哪些程序元素上(類、結(jié)構(gòu)、屬性和方法等)它是否可以多次應(yīng)用到同一個程序元素上特性在應(yīng)用到類或接口上時(shí),是否由派生類和接口繼承這個特性有哪些必選和可選參數(shù)如果編譯器找不到對應(yīng)的特性類,或者找到一個這樣的特性類,但使用特性的方式與 特性類中的信息不匹配,編譯器就會產(chǎn)生一個編譯錯誤。例如,如果特性類指定該特性只 能應(yīng)用于字段,但我們把它應(yīng)用到結(jié)構(gòu)定義上,就會產(chǎn)生一個編譯錯誤。繼續(xù)上面的示例,假定定義了一個FieldName特性:AttributeUsage(AttributeTargets.P

7、roperty,AllowMultiple=false,lnherited=false)public class FieldNameAttribute : Attributeprivate string name;public FieldNameAttribute(string name) = name;下面幾節(jié)討論這個定義中的每個元素。1. AttributeUsage 特性要注意的第一個問題是特性(attribute)類本身用一個特性System.AttributeUsage來標(biāo)記。這是Microsoft定義的一個特性,C#編譯器為它提供了特殊的支持(AttributeU

8、sage根本不是一個特性,它更像一個元特性,因?yàn)樗荒軕?yīng)用到其他特性上,不能應(yīng)用到類上)。AttributeUsage主要用于表示定制特性可以應(yīng)用到哪些類型的程序元素上。這些信息由它的第一個參數(shù)給出,該參數(shù)是必選的,其類型是枚舉類型AttributeTargets。在上面的示例中,指定FieldName特性只能應(yīng)用到屬性(property)上這是因?yàn)槲覀冊谇懊娴拇a段中把它應(yīng)用到屬性上。AttributeTargets枚舉的成員如下: All Assembly Class Con structor Delegate En um Event Field GenericParameter(僅.NE

9、T 2.0 提供) In terface Method Module Parameter Property ReturnValue Struct這個列表列出了可以應(yīng)用該特性的所有程序元素。注意在把特性應(yīng)用到程序元素上時(shí),應(yīng)把特性放在元素前面的方括號中。但是,在上面的列表中,有兩個值不對應(yīng)于任何 程序元素:Assembly和Module。特性可以作為一個整體應(yīng)用到程序集或模塊中,而不是 應(yīng)用到代碼中的一個元素上,在這種情況下,這個特性可以放在源代碼的任何地方,但需 要用關(guān)鍵字assembly或module來做前綴:assembly: SomeAssemblyAttribute(Parameter

10、s)module: SomeAssemblyAttribute(Parameters)在指定定制特性的有效目標(biāo)元素時(shí),可以使用按位OR運(yùn)算符把這些值組合起來。例如,如果指定 FieldName特性可以應(yīng)用到屬性和字段上,可以編寫下面的代碼:AttributeUsage(AttributeTargets.Property | AttributeTargets.Field,AllowMultiple=false, lnherited=false) public class FieldNameAttribute : Attribute也可以使用AttributeTargets.All指定特性可以應(yīng)用

11、到所有類型的程序元素上。AttributesUsage特性還包含另外兩個參數(shù)AllowMultiple 和Inherited。它們用不同的語法來指定:= ,而不是只給出這些參數(shù)的值。這些參數(shù)是可選的,如 果需要,可以忽略它們。AllowMultiple參數(shù)表示一個特性是否可以多次應(yīng)用到同一項(xiàng)上,這里把它設(shè)置為false,表示如果編譯器遇到下述代碼,就會產(chǎn)生一個錯誤:FieldName(SocialSecurityNumber)FieldName(NationallnsuranceNumber)public string SocialSecurityNumber/ etc.如果Inherited

12、參數(shù)設(shè)置為true,就表示應(yīng)用到類或接口上的特性也可以自動應(yīng)用到所 有派生的類或接口上。如果特性應(yīng)用到方法或?qū)傩陨希部梢宰詣討?yīng)用到該方法或?qū)傩缘?重載上。2. 指定特性參數(shù)下面介紹如何指定定制特性的參數(shù)。在編譯器遇到下述語句時(shí):FieldName(SocialSecurityNumber)public string SocialSecurityNumber/ etc.會檢查傳送給特性的參數(shù) (在本例中,是一個字符串 ),并查找該特性中帶這些參數(shù)的 構(gòu)造函數(shù)。如果找到一個這樣的構(gòu)造函數(shù),編譯器就會把指定的元數(shù)據(jù)傳送給程序集。如 果找不到,就生成一個編譯錯誤。如后面所述,反射會從程序集中讀取元數(shù)

13、據(jù),并實(shí)例化 它們表示的特性類。因此,編譯器需要確保存在這樣的構(gòu)造函數(shù),才能在運(yùn)行期間實(shí)例化 指定的特性。在本例中,僅為 FieldNameAttribute 提供了一個構(gòu)造函數(shù),而這個構(gòu)造函數(shù)有一個字 符串參數(shù)。因此,在把 FieldNameAttribute特性應(yīng)用到一個屬性上時(shí),必須為它提供一個 字符串參數(shù),如上面的代碼所示。如果可以選擇特性的參數(shù)類型,當(dāng)然可以提供構(gòu)造函數(shù)的不同重載方法,但一般是僅 提供一個構(gòu)造函數(shù),使用屬性來定義其他可選參數(shù),下面將介紹可選參數(shù)。3. 指定特性的可選參數(shù)在AttributeUsage特性中,可以使用另一個語法,把可選參數(shù)添加到特性中。這個語 法指定可選

14、參數(shù)的名稱和值,處理特性類中的公共屬性或字段。例如,假定修改SocialSecurityNumber屬性的定義,如下所示:FieldName(SocialSecurityNumber,Comment=This is the primary key field)public string SocialSecurityNumber/ etc.在本例中,編譯器識別第二個參數(shù)的語法=,所以不會把這個參數(shù)傳遞給FieldNameAttribute構(gòu)造函數(shù),而是查找一個有該名稱的公用屬性或字段(最好不要使用公用字段,所以一般情況下要使用屬性),編譯器可以用這個屬性設(shè)置第二個參數(shù)的值。如果希望上面的代碼工作

15、,必須給FieldNameAttribute添加一些代碼:AttributeUsage(AttributeTargets.Property,AllowMultiple=false, lnherited=false) public class FieldNameAttribute : Attribute private string comment;public string Commentgetreturn comment;setcomment = value; / etc.12.1.2 定制特性示例: WhatsNewAttributes本節(jié)開始編寫前面描述過的示例 WhatsNewAttr

16、ibutes,該示例提供了一個特性,表示 最后一次修改程序元素的時(shí)間。這個示例比前面所有的示例都復(fù)雜,因?yàn)樗?個不同的程序集: WhatsNewAttributes程序集,它包含特性的定義。 VectorClass程序集,包含所應(yīng)用的特性的代碼。 LookUpWhatsNew程序集,包含顯示已改變的數(shù)據(jù)項(xiàng)信息的項(xiàng)目。當(dāng)然,只有LookUpWhatsNew是前面使用的一個控制臺應(yīng)用程序,其余兩個程序集都是庫文件,它們都包含類的定義,但都沒有程序的入口。對于VectorClass程序集,我們使用了 VectorAsCollection示例,但刪除了入口和測試代碼類,只剩下 Vector類。在命

17、令行上編譯,以此管理3個相關(guān)的程序集要求較高的技巧,所以我們分別給出編譯這3個源文件的命令。也可以編輯代碼示例,(可以從 Wrox Press網(wǎng)站上下載),組合為一個Visual Studio 2005解決方案,詳見第14章。下載的文件包含所需的 Visual Studio 2005 解決方案文件。1. WhatsNewAttributes庫程序集首先從核心的 WhatsNewAttributes程序集開始。其源代碼包含在文件WhatsNewAttributes.cs中,該文件位于本章示例代碼的WhatsNewAttributes解決方案的WhatsNewAttributes項(xiàng)目中。編譯為庫的

18、語法非常簡單:在命令行上,給編譯器提供標(biāo)記target:library即可。要編譯 WhatsNewAttributes,鍵入:csc /target:library WhatsNewAttributes.csWhatsNewAttributes.cs 文件定義了兩個特性類LastModifiedAttribute 和 SupportsWhatsNew-Attribute 。 LastModifiedAttribute 特性可以用于標(biāo)記最后一次修改數(shù)據(jù)項(xiàng)的時(shí)間,它有 兩個必選參數(shù)(該參數(shù)傳遞給構(gòu)造函數(shù));修改的日期和包含描述修改的字符串。它還有一個可選參數(shù)Issues (表示存在一個公共屬性)

19、,它可以描述該數(shù)據(jù)項(xiàng)的任何重要問題。在現(xiàn)實(shí)生活中,或許想把特性應(yīng)用到任何對象上。為了使代碼比較簡單,這里僅允許 將它應(yīng)用于類和方法,并允許它多次應(yīng)用到同一項(xiàng)上(AllowMultiple=true),因?yàn)榭梢远啻涡薷囊粋€項(xiàng),每次修改都需要用一個不同的特性實(shí)例來標(biāo)記。SupportsWhatsNew是一個較小的類,表示不帶任何參數(shù)的特性。這個特性是一個程序集的特性,用于把程序集標(biāo)記為通過LastModifiedAttribute 維護(hù)的文檔說明書。這樣,以后查看這個程序集的程序會知道,它讀取的程序集是我們使用自動文檔說明過程生成的那 個程序集。這部分示例的完整源代碼如下所示:using Syst

20、em;namespace Wrox.ProCSharp.WhatsNewAttributes AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,AllowMultiple=true, lnherited=false)public class LastModifiedAttribute : Attributeprivate DateTime dateModified;private string changes;private string issues;public LastModifiedAttribute(str

21、ing dateModified, string changes)this.dateModified = DateTime.Parse(dateModified); this.changes = changes;public DateTime DateModifiedgetreturn dateModified;public string Changesgetreturn changes;public string Issuesgetreturn issues;setissues = value;AttributeUsage(AttributeTargets.Assembly)public c

22、lass SupportsWhatsNewAttribute : Attributeset訪問器提供給 這些參數(shù)都是必從上面的描述可以看出,上面的代碼非常簡單。但要注意,不必將 Changes和DateModified屬性,不需要這些訪問器是因?yàn)樵跇?gòu)造函數(shù)中, 選參數(shù)。需要get訪問器,是因?yàn)橐院罂梢宰x取這些特性的值。2. VectorClass 程序集本節(jié)就使用這些特性,我們用前面的VectorAsCollecti on示例的修訂版本來說明。注意這里需要引用剛才創(chuàng)建的WhatsNewAttributes庫,還需要使用 using語句指定相應(yīng)的命名空間,這樣編譯器才能識別出這些特性:using

23、 System;using System.Collections;using System.Text;using Wrox.ProCSharp.WhatsNewAttributes;assembly: SupportsWhatsNew在這段代碼中,添加了一行用SupportsWhatsNew特性標(biāo)記程序集本身的代碼。下面考慮Vector類的代碼。我們并不是真的要修改這個類中的任何內(nèi)容,只是添加兩 個LastModified特性,以標(biāo)記出本章對 Vector類進(jìn)行的操作。把 Vector定義為一個類,而 不是結(jié)構(gòu),以簡化后面顯示特性所編寫的代碼(在VectorAsCollection示例中,Ve

24、ctor是一個結(jié)構(gòu),但其枚舉器是一個類。于是,這個示例的下一個版本在查看程序集時(shí),必須同時(shí) 考慮類和結(jié)構(gòu)。這會使例子比較復(fù)雜)。namespace Wrox.ProCSharp.VectorClassLastModified(14 Feb 2007, Enumerable interface implemented +So Vector can now be treated as a collection)LastModified(10 Feb 2007, IFormattable interface implemented +So Vector now responds to format

25、specifiers N and VE)class Vector : IFormattable, IEnumerablepublic double x, y, z;public Vector(double x, double y, double z)this.x = x;this.y = y;this.z =乙LastModified(10 Feb 2002,Method added in order to provide formatting support)public string ToString(stringformat, IFormatProvider formatProvider

26、)if (format = null)return ToString();再把包含的VectorEnumerator類標(biāo)記為new:LastModified(14 Feb 2007,Class created as part of collection support for Vector)private class VectorEnumerator : lEnumerator為了在命令行上編譯這段代碼,應(yīng)鍵入下面的命令:csc /target:library /reference:WhatsNewAttributes.dll VectorClass.es上面是這個示例的代碼。目前還不能運(yùn)行它

27、,因?yàn)槲覀冎挥袃蓚€庫。在描述了反射的 工作原理后,就介紹這個示例的最后一部分,查找和顯示這些特性。12.2 反射本節(jié)先介紹System.Type類,通過這個類可以訪問任何給定數(shù)據(jù)類型的信息。然后簡 要介紹System.Reflection.Assembly類,它可以用于訪問給定程序集的信息,或者把這個程 序集加載到程序中。最后把本節(jié)的代碼和上一節(jié)的代碼結(jié)合起來,完成 WhatsNewAttributes示例。12.2.1 System.Type 類在本書中的許多場合中都使用了Type類,但它只存儲類型的引用:Type t = typeof(double)我們以前把Type看作一個類,但它實(shí)際上

28、是一個抽象的基類。只要實(shí)例化了一個Type對象,就實(shí)例化了Type的一個派生類。Type有與每種數(shù)據(jù)類型對應(yīng)的派生類,但一般情況下派生的類只提供各種Type方法和屬性的不同重載,返回對應(yīng)數(shù)據(jù)類型的正確數(shù)據(jù)。一般不增加新的方法或?qū)傩?。獲取指向給定類型的Type引用有3種常用方式:使用C#的typeof運(yùn)算符,如上所示。這個運(yùn)算符的參數(shù)是類型的名稱(不放在引號中)。使用GetType()方法,所有的類都會從System.Object繼承這個類。double d = 10;Type t = d.GetType();在一個變量上調(diào)用GetType(),而不是把類型的名稱作為其參數(shù)。但要注意,返回的Ty

29、pe對象仍只與該數(shù)據(jù)類型相關(guān):它不包含與類型實(shí)例相關(guān)的任何信息。如果有一個對象 引用,但不能確保該對象實(shí)際上是哪個類的實(shí)例,這個方法也是很有用的。 還可以調(diào)用 Type類的靜態(tài)方法 GetType():Type t = Type.GetType(System.Double);Type是許多反射技術(shù)的入口。它執(zhí)行許多方法和屬性,這里不可能列出所有的方法和 屬性,而主要介紹如何使用這個類。注意,可用的屬性都是只讀的:可以使用Type確定數(shù)據(jù)的類型,但不能使用它修改該類型!1. Type的屬性由Type執(zhí)行的屬性可以分為下述3類:有許多屬性都可以獲取包含與類相關(guān)的各種名稱的字符串,如表12-1所示。

30、表 12-1屬性返回值Name數(shù)據(jù)類型名FullName數(shù)據(jù)類型的完全限定名(包括命名空間名)Namespace定義數(shù)據(jù)類型的命名空間名屬性還可以進(jìn)一步獲取 Type對象的引用,這些引用表示相關(guān)的類,如表12-2所示。表 12-2屬性返回對應(yīng)的Type引用BaseType這個Type的直接基本類型UnderlyingSystemType這個Type在.NET運(yùn)行庫中映射的類型(某些.NET基類實(shí)際上映射由IL識別的特定預(yù)定義類型)許多Boolean屬性表示這個類型是一個類、還是一個枚舉等。這些屬性包括IsAbstract、IsArray、IsClass、IsEnum、IsInteface、Is

31、Pointer、lsPrimitive( 種預(yù)定義的基本數(shù) 據(jù)類型卜 IsPublic、IsSealed 和 IsValueType例如,使用一個基本數(shù)據(jù)類型:Type intType = typeof(int);Console.WriteLine(intType.lsAbstract);/ writes falseConsole.WriteLine(intType.lsClass);/ writes falseConsole.WriteLine(intTypesEnum);/ writes falseConsole.WriteLine(intType .I sPrimitive);/ wri

32、tes trueConsole.WriteLine(intType.lsValueType);/ writes true或者使用Vector類:Type intType = typeof(Vector);Console.WriteLine(intType.lsAbstract);/ writes falseConsole.WriteLine(intType.lsClass);/ writes trueConsole.WriteLine(intTypesEnum);/ writes falseConsole.WriteLine(intType .I sPrimitive);/ writes fa

33、lseConsole.WriteLine(intType.lsValueType);/ writes false也可以獲取定義類型的程序集的引用,該引用作為System.Reflection.Assembly類實(shí)例的一個引用來返回:Type t = typeof (Vector);Assembly containingAssembly = new Assembly(t);2.方法System.Type的大多數(shù)方法都用于獲取對應(yīng)數(shù)據(jù)類型的成員信息:構(gòu)造函數(shù)、屬性、方法和事件等。它有許多方法,但它們都有相同的模式。例如,有兩個方法可以獲取數(shù)據(jù)類 型的方法信息: GetMethod()和 GetMe

34、thods() 。 GetMethod()方法返回 System.Reflectio n.Methodl nfo 對象的一個引用,其中包含一個方法的信息。GetMethods()返回這種引用的一個數(shù)組。其區(qū)別是GetMethods()返回所有方法的信息,而GetMethod()返回一個方法的信息,其中該方法包含特定的參數(shù)列表。這兩個方法都有重載方法,該重 載方法有一個附加的參數(shù),即Bin di ngFlags枚舉值,表示應(yīng)返回哪些成員,例如,返回公有成員、實(shí)例成員和靜態(tài)成員等。例如,GetMethods()最簡單的一個重載方法不帶參數(shù),返回?cái)?shù)據(jù)類型所有公共方法的 信息:Type t = typ

35、eof(double);MethodInfo methods = t.GetMethods(); foreach (MethodInfo nextMethod in methods) / etc.Type的成員方法如表12-3所示遵循同一個模式。表 12-3返回的對象類型方法(名稱為復(fù)數(shù)形式的方法返回一個數(shù)組)ConstructorInfoGetConstructor(), GetConstructors()EventInfoGetEvent(), GetEvents()FieldInfoGetField(), GetFields()InterfaceInfoGetInterface(), G

36、etInterfaces()MemberInfoGetMember(), GetMembers()MethodInfoGetMethod(), GetMethods()PropertyInfoGetProperty(), GetProperties()GetMember()和GetMembers()方法返回?cái)?shù)據(jù)類型的一個或所有成員的信息,這些成員 可以是構(gòu)造函數(shù)、屬性和方法等。最后要注意,可以調(diào)用這些成員,其方式是調(diào)用Type的 InvokeMember()方法,或者調(diào)用 Methodinfo, PropertyInfo 和其他類的 Invoke()方法。12.2.2 TypeView 示例下

37、面用一個短小的示例 TypeView來說明Type類的一些功能,這個示例可以列出數(shù)據(jù)類型的所有成員。本例中主要介紹double型的TypeView用法,也可以修改該樣列中的一行代碼,使用其他的數(shù)據(jù)類型。TypeView提供的信息要比在控制臺窗口中顯示的信息多得多,所以我們將打破常規(guī),在一個消息框中顯示這些信息。運(yùn)行double型的TypeView示例,結(jié)果如圖12-1所示。Type Narr Dcdble Full System DoubleSystem Ba5i TypEJ.ValufcTypE UndcrlyingSystcrn Type PgublcPUBUC MEM3ERSSyelei

38、n.DDuHij Fsed MfnValue Syelem-DouNe he*d hrtaxVius Sslem.DQuNe Fseid Epsfcfl Syslem.DouNe F創(chuàng) N-egalFInfinily SyslerYi.DDubie F-eld Postwlnfiniiy Sysm.Doijble F寂d 曲 Syslem.Double Meflhod ToSlnng Sysletn.Double 曲had CellpeCode Syfilenh.Double- hSMhad ToSInhg SySlSm DciuHe MShod CmpreTd Sy dim DduNi- W

39、teShnd GnlHashCodi!- Sylvm Dnublt htehod Equals Sysivn.DDubIt htahodT祠啊 Sysleni Double Mshod Islnfhisy Sy&1em.Double Mtehad hPbsit桃 1血岬 SyBlem.DouNe Mhod leNsrlrsielnfinil S-jrBlem.Double 腳h唧 IbN4 Syslefm.Dnubie 卿hod ToSlnrg Syslem.DciulMe Mhod Panae Syslmi.Double Method Syslem.DouNe Mteihad Raise S

40、yfler九匸mubl色 hSHhad Me証 Syilern.DuuHfr bteflhiid Tr Parst Sydsni.Objeci EMcthod GuiTypc圖 12-1該消息框顯示了數(shù)據(jù)類型的名稱、全名和命名空間,以及底層類型和基類的名稱。然 后迭代該數(shù)據(jù)類型的所有公有實(shí)例成員,顯示所聲明類型的每個成員、成員的類型(方法、字段等)以及成員的名稱。聲明類型是實(shí)際聲明 類型成員的類名(換言之,如果在 System.Double中定義或重載, 該聲明類型就是 System.Double ,如果成員繼承了某個基類, 該聲明類就是相關(guān)基類的名稱)。TypeView不會顯示方法的簽名,因

41、為我們是通過Memberlnfo對象獲取所有公有實(shí)例成員的信息,參數(shù)信息不能通過MemberInfo對象來獲得。為了獲取該信息,需要引用MemberInfo和其他更特殊的對象,即需要分別獲取每一個成員類型的信息。TypeView會顯示所有公有實(shí)例成員的信息,但對于 double來說,僅定義了字段和方 法。把TypeView編譯為一個控制臺應(yīng)用程序,可以在控制臺應(yīng)用程序中顯示消息框。但 是,使用消息框就意味著需要引用基類程序集System.Windows.Forms. dll,它包含System.Windows.Forms命名空間中的類,在這個命名空間中,定義了我們需要的 MessageBox類

42、。下面列出 TypeView的代碼。開始時(shí)需要添加兩條using語句:using System;using System.Text;using System.Windows.Forms;using System.Reflection;需要System.Text的原因是我們要使用StringBuilder對象建立在消息框中顯示的文本,以及消息框本身的System.Windows.Forms。全部代碼都放在類MainClass中,這個類包含兩個靜態(tài)方法和一個靜態(tài)字段,StringBuilder的一個實(shí)例叫作OutputText,用于創(chuàng)建在消息框中顯示的文本。Main方法和類的聲明如下所示:clas

43、s MainClassStatic StringBuilder OutputText = new StringBuilder();static void Main()/ modify this line to retrieve details of any/ other data typeType t = typeof(double);AnalyzeType(t);MessageBox.Show(OutputText.ToString(), Analysis of type + t.Name);Console.ReadLine();Main()方法首先聲明一個Type對象,表示我們選擇的數(shù)據(jù)類

44、型,再調(diào)用方法AnalyzeType(),從Type對象中提取信息, 并使用該信息建立輸出文本。最后在消息框中顯示輸出。使用 MessageBox類是非常直觀的:只需調(diào)用其靜態(tài)方法Show(),給它傳遞兩個字符串,分別為消息框中的文本和標(biāo)題。這些都由AnalyzeType()來完成:static void AnalyzeType(Type t)AddToOutput(Type Name: + t.Name);AddToOutput(Full Name: + t.FullName);AddToOutput(Namespace: + t.Namespace);Type tBase = t.Base

45、Type;if (tBase != null)AddToOutput(Base Type: + tBase.Name);Type tUnderlyingSystem = t.UnderlyingSystemType;if (tUnderlyingSystem != null)AddToOutput(UnderlyingSystemType: + tUnderlyingSystem.Name);AddToOutput(nPUBLIC MEMBERS:);MemberInfo Members = t.GetMembers();foreach (MemberInfo NextMember in Me

46、mbers)AddToOutput(NextMember.DeclaringType + + NextMember.MemberType + + NextMember.Name);執(zhí)行這個方法,僅需調(diào)用Type對象的各種屬性,就可以獲得我們需要的類型名稱的信 息,再調(diào)用 GetMembers()方法,獲得一個 Memberlnfo對象數(shù)組,該數(shù)組用于顯示每個成 員的信息。注意這里使用了一個輔助方法 AddToOutput(),該方法創(chuàng)建要在消息框中顯示的 文本:static void AddToOutput(string Text) OutputText.Append(n + Text);使用

47、下面的命令編譯TypeView程序集:csc /reference:System.Windows.Forms.dll TypeView.cs12.2.3 Assembly 類Assembly類是在System.Reflection命名空間中定義的,它允許訪問給定程序集的元數(shù)據(jù),它也包含可以加載和執(zhí)行程序集(假定該程序集是可執(zhí)行的)的方法。與Type類一樣, Assembly類包含非常多的方法和屬性,這里不可能逐一論述。下面僅介紹完成示例WhatsNewAttributes所需要的方法和屬性。在使用Assembly實(shí)例做一些工作前,需要把相應(yīng)的程序集加載到運(yùn)行進(jìn)程中。為此,可以使用靜態(tài)成員Ass

48、embly.Load()或 Assembly.LoadFrom()。這兩個方法的區(qū)別是Load()的參數(shù)是程序集的名稱,運(yùn)行庫會在各個位置上搜索該程序集,這些位置包括本地目錄和全局程序集高速緩存。而LoadFrom()的參數(shù)是程序集的完整路徑名,不會在其他位置搜索該程序集:Assembly assembly1 = Assembly.Load(SomeAssembly);Assembly assembly2 = Assembly.LoadFrom(C:My ProjectsSoftwareSomeOtherAssembly);這兩個方法都有許多其他重載,它們提供了其他安全信息。加載了一個程序集后

49、,就可以使用它的各種屬性,例如查找它的全名:string name = assembly1.FullName;1.查找在程序集中定義的類型Assembly類的一個特性是可以獲得在相應(yīng)程序集中定義的所有類型的信息,只要調(diào)用Assembly.GetTypes()方法,就可以返回一個包含所有類型信息的System.Type引用數(shù)組,然后就可以按照上一節(jié)的方式處理這些Type引用了:Type types = theAssembly.GetTypes(); foreach(Type definedType in types)DoSomethingWith(definedType);2.查找定制特性用于查

50、找在程序集或類型中定義了什么定制特性的方法取決于與該特性相關(guān)的對象類 型。如果要確定程序集中有什么定制特性,就需要調(diào)用Attribute類的一個靜態(tài)方法GetCustomAttributes(),給它傳遞程序集的引用:Attribute definedAttributes =Attribute.GetCustomAttributes(assembly1);/ assembly1 is an Assembly object注意:這是相當(dāng)重要的。以前您可能想知道,在定義定制特性時(shí),必須為它們編寫類,為什 么Microsoft沒有更簡單的語法。答案就在于此。定制特性與對象一樣,加載了程序集后, 就可

51、以讀取這些特性對象,查看它們的屬性,并且調(diào)用它們的方法。GetCustomAttributes()在用于獲取程序集的特性時(shí),有兩個重載方法:如果在調(diào)用它時(shí),除了程序集的引用外,沒有指定其他參數(shù),該方法就會返回為這個程序集定義的所有定制 特性。當(dāng)然,也可以通過指定第二個參數(shù)來調(diào)用它,第二個參數(shù)表示特性類的一個Type對象,在這種情況下,GetCustomAttributes()就返回一個數(shù)組,該數(shù)組包含該特性類的所有特性。注意,所有的特性都作為一般的Attribute引用來獲取。如果要調(diào)用為定制特性定義的任何方法或?qū)傩?,就需要把這些引用顯式轉(zhuǎn)換為相關(guān)的定制特性類。調(diào)用 Assembly.GetC

52、ustomAttributes()的另一個重載方法,可以獲得與給定數(shù)據(jù)類型相關(guān)的定制特 性信息,這次傳遞的是一個 Type引用,它描述了要獲取的任何相關(guān)特性的類型。另一方面,如果要獲得與方法、構(gòu)造函數(shù)和字段等相關(guān)的特性,就需要調(diào)用GetCustomAttributes()方法,該方法是類 Methodinfo、 Constructorlnfo 和 Fieldlnfo 等的一個成員。如果只需要給定類型的一個特性,就可以調(diào)用GetCustomAttribute()方法,它返回一個Attribute 對象。在 WhatsNewAttributes 示例中使用 GetCustomAttribute()

53、方法,是為了確定 程序集中是否有特性 SupportsWhatsNew。為此,調(diào)用GetCustomAttributes(),傳遞對WhatsNew Attributes 程序集的一個引用和SupportWhatsNewAttribute特性的類型。如果有這個特性,就返回一個Attribute實(shí)例。如果在程序集中沒有定義任何實(shí)例,就返回null。如果找到兩個或多個實(shí)例,GetCustomAttribute()方法就拋出一個異常System.Reflection.AmbiguousMatchException :Attribute supportsAttribute =Attribute.Get

54、CustomAttributes(assembly1, typeof(SupportsWhats NewAttribute);12.2.4 完成 WhatsNewAttributes 示例現(xiàn)在已經(jīng)有足夠的知識來完成WhatsNewAttributes示例了。為該示例中的最后一個程序集LookUpWhatsNew編寫源代碼,這部分應(yīng)用程序是一個控制臺應(yīng)用程序,它需要引用其他兩個程序集 WhatsNewAttributes和VectorClass。這是一個命令行應(yīng)用程序,但仍可以 象前面的TypeView示例那樣在消息框中顯示結(jié)果,因?yàn)榻Y(jié)果是許多文本,所以不能顯示 在一個控制臺窗口屏幕上。這個文件

55、的名稱為LookUpWhatsNew.cs,編譯它的命令是:esc /reference:WhatsNewAttributes.dll /reference:VectorClass.dllLookUpWhatsNew.cs在這個文件的源代碼中,首先指定要使用的命名空間System.Text,因?yàn)樾枰褂靡粋€StringBuilder 對象:using System;using System.Reflection;using System.Windows.Forms;using System.Text;using Wrox.ProCSharp.VectorClass;using Wrox.ProCSharp.WhatsNewAttributes;na

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論