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