在項(xiàng)目中,程序集間的相互引用是經(jīng)常遇到的。比如,主程序引用各分模塊,各分模塊引用公用程序集,以及平行的程序集間為了某些功能的實(shí)現(xiàn)也需要相互引用。這樣的引用一方面是迫不得已的選擇,而另一方面也反映出系統(tǒng)設(shè)計的水平。下面,簡單介紹一下C#中的一種機(jī)制——反射。反射可以在避免某些情況下的程序集引用問題,比如主程序引用各功能模塊的問題,當(dāng)然其它模塊間也是可以用反射的,只是使用是否方便這些問題需要在使用前根據(jù)實(shí)際情況進(jìn)行考慮。本文以主程序加載分模塊為例,介紹一下反射的使用。
所謂反射,就是對程序集或模塊利用基礎(chǔ)類型進(jìn)行解析,然后還原出一個對象模型,在調(diào)用者工作域里運(yùn)行的一個過程。其核心部分就是解析。工作原理是這樣的。
無論你創(chuàng)建的多么結(jié)構(gòu)復(fù)雜的類,歸根結(jié)底都是由元數(shù)據(jù)構(gòu)成的。如下,
public class Person { private string name; private int age; private string content; }
在程序編譯時,編譯器會創(chuàng)建類型表,字段表,方法表或其它表。再利用System.Reflection命名空間中的包含的類型進(jìn)行解析,也可以看成對比的過程,將要被反射的程序集中的表讀出,根據(jù)System.Reflection的基本類型,進(jìn)行重組,從而還原出原來程序集的結(jié)構(gòu)。
例如,序列化的過程就是使用了反射,序列化格式器將被序列化的對象中的字段的值獲取出來,然后寫入一個字節(jié)流,進(jìn)行傳輸;因?yàn)樽止?jié)流傳輸不容易出錯或信息丟失。接收到字節(jié)流后,根據(jù)基本類型再還原出原對象的模型。
反射中,System.Type類型很重要,它遍歷被反射的表中的類型和反射中的基本類型進(jìn)行比較,然后判斷出當(dāng)前是什么類型。
簡單了解了原理,那么再看如何使用的。
建一個工程,包含主程序和子程序集,如圖
主程序生成在SetupApp文件夾中,子程序生成在\SetupApp\Library\中。
子程序的程序入口需要遵循一些約定,比如入口類名字需要都一樣,這樣才可統(tǒng)一加載。
namespace ReflecLibrary2 { public class MainWindow { public MainWindow() { welcome(); } private void Welcome() { Console.Write(@"當(dāng)前程序?yàn)椋篟eflecLibrary2 "); Console.WriteLine(@"開始執(zhí)行ReflecLibrary2!"); } } } namespace ReflectLibrary1 { public class MainWindow { public MainWindow() { welcome(); } private void Welcome() { Console.Write(@"當(dāng)前程序?yàn)椋篟eflectLibrary1 "); Console.WriteLine(@"開始執(zhí)行ReflecLibrary1!"); } } }
然后看調(diào)用的部分,
class Program { static void Main(string[] args) { /////////////////////設(shè)置約定的規(guī)則,比如需要加載的程序的目錄,程序集程序入口的類/////////////////// string startPath = AppDomain.CurrentDomain.BaseDirectory + @"Library\"; string suffix=@".dll"; string commonMainClass = @"MainWindow"; DirectoryInfo directory = new DirectoryInfo(startPath); /////////////////////將程序集文件名讀入,這里其實(shí)只需要string類型的路徑即可, //////為了后面處理字符串方便所以才讀取文件信息 var libraries = directory.GetFiles().OrderBy(o=>o.FullName); ListloadDlls = new List (); if (libraries != null) { foreach (FileInfo item in libraries) { if (item.FullName.ToLower().EndsWith(suffix)) { loadDlls.Add(item); } } } /////////////////////執(zhí)行程序集/////////////////// //程序集1 Assembly assembly1 = Assembly.LoadFile(loadDlls[0].FullName.Replace(@"/", @"\")); string typeName1 = loadDlls[0].Name.Replace(loadDlls[0].Extension,string.Empty) + @"." + commonMainClass; assembly1.CreateInstance(typeName1); //程序集2 Assembly assembly2 = Assembly.LoadFile(loadDlls[1].FullName.Replace(@"/", @"\")); string typeName2 = loadDlls[1].Name.Replace(loadDlls[0].Extension, string.Empty) + @"." + commonMainClass; assembly2.CreateInstance(typeName2); Console.ReadLine(); }
各個部分的作用都寫在了注釋中。
運(yùn)行結(jié)果就是,程序集1和程序集2中的方法都執(zhí)行了。當(dāng)然這里只是為了方便說明只寫了一個方法,實(shí)際上
public MainWindow()
{
welcome();
}
就是子程序的入口。
結(jié)果如下,
那么反射我們就有了一個直觀的理解,里面的詳細(xì)原理,下一篇繼續(xù)介紹
代碼下載
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。