面試例題8:如何動態(tài)加載外部程序集并用反射獲取指定類型的信息?
考點:學習動態(tài)加載外部程序集的基本方法,理解Assembly類的Load()方法和LoadFrom()方法的區(qū)別。 出現(xiàn)頻率:★★★ 解答 通過System.Reflection命名空間下的Assembly類可以動態(tài)加載外部程序集,可選方法為Load()方法和 LoadFrom()方法。Load()方法用于加載當前程序集位于相同目錄下的外部程序集,LoadFrom()方法可以加載其他目錄中的程序集。以上示例中的ClassRef.exe程序作為需要加載的外部程序集,進一步獲取其指定類型的信息。在目錄下新建一個程序文件,并命名為 AppClassRef.cs,編寫代碼如代碼7.8所示。 代碼7.8 動態(tài)加載外部程序集: +展開
-C#
using System;
//導入相應的命名空間 using System.Reflection; using System.IO; class AppClassRef { static void Main(string[] args) { //查看當前應用程序域的所有程序集 DisAllAm(); while (true) { Console.Write("請輸入所檢測的類型名稱:"); //接收用戶輸入值并賦值給input變量 string input = Console.ReadLine(); //如果用戶輸入"quit",則跳出循環(huán) if (input == "quit") { break; } //聲明Assembly類型對象am Assembly am; try { //調(diào)用Assembly類的Load方法,將引用傳遞給am am = Assembly.Load("ClassRef"); //以下代碼調(diào)用Assembly類的LoadFrom方法 //am = Assembly.LoadFrom(@"D:\web\NET\ClassRef.exe"); //調(diào)用am的GetType方法,并將Type對象引用返回給tp變量 Type tp = am.GetType(input, false, false); //調(diào)用ClassB的Ref靜態(tài)方法,并傳遞tp對象 ClassB.Ref(tp); } //捕獲文件未找到異常 catch (FileNotFoundException e) { //輸出異常信息 Console.WriteLine("異常信息:{0}", e.Message); } //捕獲空對象引用異常 catch (NullReferenceException e) { //輸出異常信息 Console.WriteLine("異常信息:{0}", e.Message); } //捕獲一般異常 catch (Exception e) { //輸出異常信息 Console.WriteLine("異常信息:{0}", e.Message); } finally { //再次查看當前應用程序域的所有程序集 DisAllAm(); } } } //定義DisAllAm方法,用于顯示程序集列表 static void DisAllAm() { Console.WriteLine("\n\t=============當前應用程序域中所有加載的程序集============="); //通過GetAssemblies方法獲取當前應用程序域的所有程序集 foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { //輸出程序集的名稱 Console.WriteLine("程序集:{0}", a.FullName); } } } class ClassB { //定義靜態(tài)方法Ref,接收一個Type類型的參數(shù) public static void Ref(Type tp) { //輸出Type對象的基本屬性 string FullName = tp.FullName.ToString(); Console.WriteLine("\n\t============={0}類型的信息=============", FullName); //獲取Type對象的所有公共成員并保存到mi數(shù)組 MemberInfo[] mi = tp.GetMembers(); //遍歷并輸出mi數(shù)組所有的子項屬性 foreach (MemberInfo m in mi) { Console.WriteLine("\t成員類別->{0},名稱->{1}",m.MemberType, m.Name); } //獲取Type對象所實現(xiàn)的接口并保存到Itp數(shù)組 Type[] Itp = tp.GetInterfaces(); //判斷Itp數(shù)組是否有子項,如果有則輸出子項屬性 if (Itp.Length != 0) { foreach (Type t in Itp) { Console.WriteLine("{0}實現(xiàn)的接口類型->{1}", FullName, t.FullName); } } else { Console.WriteLine("{0}不實現(xiàn)的任何接口類型", FullName); } } } 本題的類型信息輸出和ClassRef.exe相同,這里不作過多講述。主程序中首先調(diào)用了DisAllAm()靜態(tài)方法,該方法封裝了列舉當前應用程序域所含程序集列表的代碼。在命令行下編譯AppClassRef.cs執(zhí)行AppClassRef程序,運行結(jié)果如圖7.13所示。 本程序首先輸出了當前應用程序域所包含程序集的列表,可知當前僅有mscorlib程序集和AppClassRef程序集被加載。繼續(xù)操作,再次調(diào)用DisAllAm()方法,所輸出的程序集列表中已經(jīng)加入了ClassRef程序集。 ![]() 圖7.13 動態(tài)加載外部程序集
注意:mscorlib程序集包含了.NET大部分的基類庫,CLR運行時自動加載。 解析 程序動態(tài)加載外部程序集,通過System.Reflection命名空間下的Assembly類實現(xiàn),該類的Load()方法和 LoadFrom()方法可以在運行時加載指定的外部程序集。加載外部程序集后,Assembly類將創(chuàng)建相應的對象,調(diào)用該對象的GetType()方法可獲取指定類型的詳細信息。假設加載D:\根目錄下的MyApp.exe程序集,并且定義Assembly類的對象am,其如以下代碼所示: 序直接輸出了ClassA類的細節(jié)信息。再次輸入"ClassB",程序輸出ClassB類的細節(jié)信息,運行結(jié)果如圖7.10所示。 +展開
-C#
using System;
//導入相應的命名空間 using System.Reflection; using System.IO; Assembly am; try { am = Assembly.Load("MyApp"); Type tp = am.GetType("指定類型名稱",false,false); } catch (FileNotFoundException e) { Console.WriteLine("異常信息:{0}", e.Message); } 以上代碼調(diào)用了Assembly類的Load()方法載入MyApp程序集(exe或dll),代碼正常加載的前提是當前程序集和MyApp程序集位于相同目錄。所以,Assembly類的LoadFrom()方法也比較常用,其編寫方法如下所示: +展開
-C#
am = Assembly.LoadFrom("D:\MyApp.exe");
可見,Assembly類的LoadFrom()方法需要傳遞外部程序集的完整路徑。當外部程序集加載后,可以通過訪問當前應用程序域的所含程序集,以確定加載是否成功。需要注意System.IO命名空間的導入,因為主程序中需要捕捉"文件未找到"的異常,防止外部程序集不存在。 說明:讀取AppDomain類的CurrentDomain屬性,可返回當前應用程序域,調(diào)用當前應用程序域的GetAssemblies方法,可獲取所包含程序集的集合。 面試例題9:如何通過晚期綁定調(diào)用方法成員? 考點:晚期綁定的含義,晚期綁定的基本方法。 出現(xiàn)頻率:★★★ 解答 晚期綁定即在編譯時不能確定是否存在類型,在運行時創(chuàng)建該類型的實例,調(diào)用其成員。本例程序分別定義了3個外部類型,編譯為dll程序集,由 LateBinding.cs代碼動態(tài)加載,調(diào)用其內(nèi)部方法。在目錄下新建一個程序文件,并命名為OldClass.cs,編寫代碼如代碼7.9所示。 代碼7.9 第1個外部類:OldClass.cs +展開
-C#
public class OldClass
{ //定義public權(quán)限的Method靜態(tài)方法 public static string Method(string s) { string output = "OldClass類的Method靜態(tài)方法返回結(jié)果:" + s; return output; } } 在目錄下新建一個程序文件,并命名為NewClass.cs,編寫代碼如代碼7.10所示。 代碼7.10 第2個外部類:NewClass.cs +展開
-C#
public class NewClass
{ //定義public權(quán)限的Method實例方法 public string Method(string s) { string output = "NewClass類的Method實例方法返回結(jié)果:" + s; return output; } } 在目錄下新建一個程序文件,并命名為MyClass.cs,編寫代碼如代碼7.11所示。 代碼7.11 第3個外部類:MyClass.cs +展開
-C#
public class MyClass
{ //定義public權(quán)限的Method實例方法 public string Method(string s) { string output = "MyClass類的Method實例方法返回結(jié)果:" + s; return output; } //定義public權(quán)限的MethodTxt實例方法 public string MethodTxt() { string output = "MyClass類的MethodTxt無參數(shù)實例方法被調(diào)用"; return output; } } |
|