|
解析
反射技術(shù)在運(yùn)行時(shí)可以獲取程序集中每個(gè)類型的成員,包括字段、方法、屬性、事件等,并進(jìn)一步獲取這些成員的詳細(xì)信息。反射技術(shù)還可以動(dòng)態(tài)載入外部程序集(私有程序集或共享程序集),獲取程序集中類型的相關(guān)數(shù)據(jù)。有意思的是從外部動(dòng)態(tài)載入的程序集還可通過晚期綁定,創(chuàng)建外部程序集中某類型的實(shí)例(對(duì)象),并且可以進(jìn)一步調(diào)用其成員(如方法和屬性)。在這個(gè)過程中,并不知道外部程序集的任何信息(甚至不知道該程序集是否存在)。 簡而言之,反射技術(shù)以編程的方式獲取程序集的元數(shù)據(jù)信息,通常情況下,只能通過ildasm.exe程序載入程序集或模塊,才能讀取其元數(shù)據(jù)。 NET的反射技術(shù)從程序集中獲取各種細(xì)節(jié)類型元數(shù)據(jù)(如FieldInfo類描述了字段的細(xì)節(jié))實(shí)例,并做進(jìn)一步的操作,而這些細(xì)節(jié)類型大多數(shù)屬于 System.Reflection命名空間。 說明:ildasm.exe是.Net Framework自帶的程序,用于查看程序集的IL代碼、元數(shù)據(jù)等信息。假設(shè)C盤是系統(tǒng)分區(qū),則ildasm.exe程序通常位于C:\WINDOWS \Microsoft.NET\ Framework\v2.0.50727目錄下。 System.Reflection命名空間包含了很多與反射有關(guān)的類型,通過這些類型可以獲取指定類型的所有細(xì)節(jié)。本題要求獲取指定類型中方法的完整信息,而System.Reflection命名空間下關(guān)于方法的類型為MethodInfo類型和ParameterInfo類型,所以只需要獲取指定類型中方法的這2個(gè)類相關(guān)的對(duì)象即可。要達(dá)到這個(gè)目的,需要獲取表示指定類型元數(shù)據(jù)的Type對(duì)象,Type對(duì)象即System.Type類的實(shí)例,該對(duì)象的成員可以返回System.Reflection命名空間下的類型,包括MethodInfo類型和ParameterInfo類型。在前面的示例中使用了對(duì)象的GetType方法獲取類型名稱,除此之外,還有多種獲取Type對(duì)象的方法,如以下代碼所示: +展開
-C#
//調(diào)用對(duì)象的GetType方法獲取Type對(duì)象的引用
Type 對(duì)象引用變量 = 對(duì)象.GetType(); //調(diào)用Type類GetType靜態(tài)方法的不同重載版本 Type 對(duì)象引用變量 = System.Type.GetType("類型的全飾名稱"); Type 對(duì)象引用變量 = System.Type.GetType("類型的全飾名稱", 是否拋出異常, 是否不區(qū)分大小寫); Type 對(duì)象引用變量 = System.Type.GetType("類型的全飾名稱, 類型所屬程序集的友好名稱"); //使用C#的typeof運(yùn)算符 Type 對(duì)象引用變量 = typeof(類型名稱); 以上代碼,調(diào)用Type類的GetType()靜態(tài)方法,其中第3個(gè)重載版本用于獲取外部私有程序集類型的Type對(duì)象。當(dāng)獲取指定類型的Type對(duì)象后,就可以通過其成員返回MethodInfo類型和ParameterInfo類型,以達(dá)到獲取方法完整信息的目的,如以下代碼所示: +展開
-C#
using System;
using System.Reflection; MethodInfo[] 方法數(shù)組 = Type.GetType("類型的全飾名稱", false, false); 使用foreach語句遍歷方法數(shù)組的每個(gè)子項(xiàng),即可訪問類型中方法的所有信息; //在foreach語句中,調(diào)用方法數(shù)組子項(xiàng)的GetParameters方法,可返回ParameterInfo類型的參數(shù)數(shù)組 ParameterInfo參數(shù)數(shù)組 = 方法數(shù)組子項(xiàng).GetParameters(); 使用foreach語句遍歷參數(shù)數(shù)組的每個(gè)子項(xiàng),即可訪問方法中參數(shù)的所有信息; 以上代碼使用了foreach語句,可訪問方法中參數(shù)的所有信息。 注意:默認(rèn)情況下,反射只能獲取公共成員的信息,而訪問非公共成員可能會(huì)帶來安全危險(xiǎn)。因此,訪問非公共成員的代碼需要帶有適當(dāng)標(biāo)志的 ReflectionPermission。此外,某些任務(wù)(例如執(zhí)行非托管代碼和序列化對(duì)象)還需要SecurityPermission。 面試?yán)}7:如何利用反射獲取當(dāng)前程序集指定類型的信息? 考點(diǎn):反射技術(shù)獲取類型信息的方法以及獲取類型成員集合的方法。 出現(xiàn)頻率:★★ 解答 獲取指定類型的信息只需要獲取該類型的Type對(duì)象,然后調(diào)用其成員即可。獲取執(zhí)行代碼封裝于ClassB類的靜態(tài)方法Ref()中,用戶輸入不同的值,反射不同類型的詳細(xì)信息。在目錄下新建一個(gè)程序文件,并命名為ClassRef.cs,編寫代碼如代碼7.7所示。 代碼7.7 反射指定類型的信息:ClassRef.cs +展開
-C#
using System;
//導(dǎo)入相應(yīng)的命名空間 using System.Reflection; class ClassRef { static void Main(string[] args) { while (true) { Console.Write("請(qǐng)輸入所檢測的類型名稱:"); //接收用戶輸入值并賦值給input變量 string input = Console.ReadLine(); //如果用戶輸入"quit",則跳出循環(huán) if (input == "quit") { break; } try { //調(diào)用Type類的靜態(tài)方法GetType,并將Type對(duì)象引用返回給tp變量 Type tp = Type.GetType(input, false, false); //調(diào)用ClassB的Ref靜態(tài)方法,并傳遞tp對(duì)象 ClassB.Ref(tp); } //捕獲空對(duì)象引用異常 catch (NullReferenceException e) { //輸出異常信息 Console.WriteLine("異常信息:{0}", e.Message); } //捕獲一般異常 catch (Exception e) { //輸出異常信息 Console.WriteLine("異常信息:{0}", e.Message); } } } } //定義2個(gè)接口類型IClassA和IClassB public interface IClassA { string MethodA(string s); } public interface IClassB { string Name { get; } } //定義ClassA,該類繼承于接口類型IClassA和IClassB class ClassA : IClassA,IClassB { public string _name; public string Name { get { return _name; } } //定義internal權(quán)限的MethodA方法 public string MethodA(string s) { _name = s; return _name; } //定義public權(quán)限的MethodB方法 public ClassA(string s) { Console.WriteLine("所接收的參數(shù)是:{0}", s); } } class ClassB { string _name; //定義internal權(quán)限的MethodB方法 internal string MethodB(string s) { _name = s; return _name; } //定義靜態(tài)方法Ref,接收1個(gè)Type類型的參數(shù) public static void Ref(Type tp) { //輸出Type對(duì)象的基本屬性 string FullName = tp.FullName; Console.WriteLine("\n\t============={0}類型的信息=============", FullName); Console.WriteLine("{0}是泛型類型嗎?->{1}", FullName, tp.IsGenericType); Console.WriteLine("{0}是接口類型嗎?->{1}", FullName, tp.IsInterface); Console.WriteLine("{0}是類類型嗎?->{1}",FullName,tp.IsClass); Console.WriteLine("{0}是COM對(duì)象嗎?->{1}", FullName, tp.IsCOMObject); Console.WriteLine("{0}是public訪問類型嗎?->{1}", FullName, tp.IsPublic); Console.WriteLine("{0}是密封類型嗎?->{1}", FullName, tp.IsSealed); Console.WriteLine("{0}是值類型嗎?->{1}", FullName, tp.IsValueType); //獲取Type對(duì)象的所有公共成員并保存到mi數(shù)組 MemberInfo[] mi = tp.GetMembers(); //遍歷并輸出mi數(shù)組所有的子項(xiàng)屬性 foreach (MemberInfo m in mi) { Console.WriteLine("\t成員類別->{0},名稱->{1}",m.MemberType, m.Name); } //獲取Type對(duì)象所支持的接口并保存到Itp數(shù)組 Type[] Itp = tp.GetInterfaces(); //判斷Itp數(shù)組是否有子項(xiàng),如果有則輸出子項(xiàng)屬性 if (Itp.Length != 0) { foreach (Type t in Itp) { Console.WriteLine("{0}實(shí)現(xiàn)的接口類型->{1}", FullName, t.FullName); } } else { Console.WriteLine("{0}不實(shí)現(xiàn)的任何接口類型", FullName); } } } |
|
|