天天看點

程式集和反射(C#)

這裡我又唠叨幾句,大家在學習的時候,如看書或者看視訊時覺得非常爽,因為感覺基本都看得懂也都挺容易的,其實看懂是一回事,你自己會動手做出來是一回事,自己能夠說出來又是另一回事了。應該把學到的東西變成自己的東西,而不是依樣畫瓢。

在說反射之前,我們先來了解一下什麼是程式集?

程式集是.net中的概念,程式集可以看作是給一堆相關類打一個包,相當于java中的jar包。

程式集包含:

資源檔案

類型中繼資料(描述在代碼中定義的每一類型和成員,二進制形式)

IL代碼(這些都被封裝在exe或dll中)

exe與dll的差別。

exe可以運作,dll不能直接運作,因為exe中有一個main函數(入口函數)。

類型中繼資料這些資訊可以通過AssemblyInfo.cs檔案來自定義。在每一個.net項目中都存在一個AssemblyInfo.cs檔案,代碼格式:

程式集和反射(C#)
程式集和反射(C#)

這些資訊在哪裡展現呢?就在我們程式集的屬性當中進行展現

程式集和反射(C#)

我們平時在安裝一些CS用戶端程式的時候,在安裝目錄下面會看見許多的程式集檔案。

使用程式集的好處

程式中隻引用必須的程式集,減小程式的尺寸。

程式集可以封裝一些代碼,隻提供必要的通路接口。

友善擴充。

如何添加程式集的引用?

直接添加程式集路徑或者添加解決方案中的項目引用。

當我們需要擴充一個程式的時候,你可能會直接在原有的項目中進行添加,那這樣的話,如果你的這些代碼想共享給别人使用呢?你就可以打包成一個程式集,然後别人隻要通過引用你這個程式集就可以進行擴充了。像我們常見的.net第三方架構庫,如log4net、unity等等。

注意:不能添加循環引用

什麼是添加循環引用?就是說A項目如果添加了B項目的項目引用,那麼此時B項目不能再添加A項目的項目引用,也就是說添加項目引用時,必須是單向的,像我們常見的三層架構之間的項目引用。

關于反射,你隻要是做.net開發,你就一定天天在用。因為VS的智能提示就是通過應用了反射技術來實作的,還有我們常用的反編譯神器Reflector.exe,看它的名字就知道了。項目中比較常見的,是通過結合配置檔案來動态執行個體化對象,如切換資料庫執行個體,或者Sprint.net的通過配置檔案來實作依賴注入等。

反射技術其實就是動态擷取程式集的中繼資料的功能,反射通過動态加載dll,然後對其進行解析,進而建立對象,調用成員。

Type是對類的描述,Type類是實作反射的一個重要的類,通過它我們可以擷取類中的所有資訊,包括方法、屬性等。可以動态調用類的屬性、方法。

反射的出現讓建立對象的方式發生了改變,因為過去面完建立對象都是直接通過new。

dll裡面有兩部分東西:IL中間語言和metadate元素據。

在.NET中反射用到命名空間是System.Reflection,這裡我先通過一個Demo來看反射能做些什麼

1、  建立控制台項目ReflectedDemo

2、  建立類庫項目My.Sqlserver.Dal

建立兩個類SqlServerHelper和SqlCmd,前者為共有類,後者為私有類

程式集和反射(C#)
程式集和反射(C#)

3、  項目ReflectedDemo,添加My.Sqlserver.Dal的項目引用,我這樣做的目的是為了友善項目ReflectedDemo中的bin目錄中時刻存在My.Sqlserver.Dal.dll程式集。

程式集和反射(C#)
程式集和反射(C#)
程式集和反射(C#)

通過ass.CreateInstance(string typeName) 和Activator.CreateInstance(Type t)方法

他們之間的差別

ass.CreateInstance(string typeName) 會動态調用類的無參構造函數建立一個對象,傳回值就是建立的對象,如果沒有無參構造函數就會報錯。

程式集和反射(C#)
程式集和反射(C#)

如果我們來修改SqlServerHelper類的代碼,添加如下構造函數:

這個時候再來運作建立執行個體的代碼就會報錯了,而編譯時是不報錯的。

程式集和反射(C#)

是以我們一般推薦使用Activator.CreateInstance方法來建立反射對象,因為此方法有許多重載,支援将參數傳遞給構造函數。

程式集和反射(C#)

此時再調用就不會出現異常了。

Type類中有三個用得比較多的方法:

bool IsAssignableFrom(Type t):是否可以從t指派,判斷目前的類型變量是不是可以接受t類型變量的指派。

bool IsInstanceOfType(object o):判斷對象o是否是目前類的執行個體,目前類可以是o的類、父類、接口

bool IsSubclassOf(Type t):判斷目前類是否是t的子類

Type類中還有一個IsAbstract屬性:判斷是否為抽象的,包含接口。

它們常用的原因是我們通過反射可以取到的東西太多了,我們需要對資料進行過濾。

添加類BaseSql,讓類SqlServerHelper繼承自BaseSql

然後檢視調用代碼:

程式集和反射(C#)
程式集和反射(C#)
程式集和反射(C#)

項目中常用的利用反射來動态切換資料庫Demo:

建立類庫項目My.Sql.IDal,并添加接口ISqlHelper。通過接口來實作資料庫操作的類的解耦,因為接口是抽象的。

添加類庫項目My.MySql.Dal,并新增類MySqlHelper.cs

My.Sqlserver.Dal、My.MySql.Dal項目分别添加對項目My.Sql.IDal的引用。讓SqlServerHelper繼承自接口ISqlHelper

程式集和反射(C#)
程式集和反射(C#)

添加App.config配置項

ReflectedDemo項目中Program.cs調用代碼:

程式集和反射(C#)
程式集和反射(C#)
程式集和反射(C#)

這樣每次需要切換資料庫時,隻要修改配置檔案就可以了。

項目結構:

程式集和反射(C#)

注意:反射雖然很強大,但卻是比較耗性能的,是以一般和緩存結合起來使用。

本文轉自鄒瓊俊部落格園部落格,原文連結:http://www.cnblogs.com/jiekzou/p/6285082.html,如需轉載請自行聯系原作者