反 射(reflection)是.net中的重要機制,通過放射,可以在執行時獲得.net中每乙個型別(包括類、結構、委託、介面和列舉等)的成員,包括 方法、屬性、事件,以及建構函式等。還可以獲得每個成員的名稱、限定符和引數等。有了反射,即可對每乙個型別瞭如指掌。如果獲得了建構函式的資訊,即可直 接建立物件,即使這個物件的型別在編譯時還不知道。
1、.net可執行應用程式結構
程式**在編譯後生成可執行的應用,我們首先要了解這種可執行應用程式的結構。
應用程式結構分為應用程式域—程式集—模組—型別—成員幾個層次,公共語言執行庫載入器管理應用程式域,這種管理包括將每個程式集載入到相應的應用程式域以及控制每個程式集中型別層次結構的記憶體布局。
程式集包含模組,而模組包含型別,型別又包含成員,反射則提供了封裝程式集、模組和型別的物件。我們可以使用反射動態地建立型別的例項,將型別繫結到現有物件或從現有物件中獲取型別,然後呼叫型別的方法或訪問其字段和屬性。反射通常具有以下用途。
(1)使用assembly定義和引導程式集,載入在程式集清單中列出模組,以及從此程式集中查詢型別並建立該型別的例項。
(2)使用module了解包含模組的程式集以及模組中的類等,還可以獲取在模組上定義的所有全域性方法或其他特定的非全域性方法。
(3)使用constructorinfo了解建構函式的名稱、引數、訪問修飾符(如pulic 或private)和實現詳細資訊(如abstract或virtual)等。使用type的getconstructors或 getconstructor方法來呼叫特定的建構函式。
(4)使用methodinfo了解方法的名稱、返回型別、引數、訪問修飾符(如pulic 或private)和實現詳細資訊(如abstract或virtual)等。使用type的getmethods或getmethod方法來呼叫特定的方法。
(5)使用fiedinfo了解欄位的名稱、訪問修飾符(如public或private)和實現詳細資訊(如static)等,並獲取或設定字段值。
(6)使用eventinfo了解事件的名稱、事件處理程式資料型別、自定義屬性、宣告型別和反射型別等,新增或移除事件處理程式。
(7)使用propertyinfo了解屬性的名稱、資料型別、宣告型別、反射型別和唯讀或可寫狀態等,獲取或設定屬性值。
(8)使用parameterinfo了解引數的名稱、資料型別、是輸入引數還是輸出引數,以及引數在方法簽名中的位置等。
system.reflection.emit命名空間的類提供了一種特殊形式的反射,可以在執行時構造型別。
反射也可用於建立稱為型別瀏覽器的應用程式,使使用者能夠選擇型別,然後檢視有關選定型別的資訊。
此外,jscript等語言編譯器使用反射來構造符號表。system.runtime.serialization命名空間中的類使用反射來訪問數 據並確定要永久儲存的字段,system.runtime.remoting命名空間中的類通過序列化來間接地使用反射。
3、在設計模式實現中使用反射技術
採用反射技術可以簡化工廠的實現。
(1)工廠方法:通過反射可以將需要實現的子類名稱傳遞給工廠方法,這樣無須在子類中實現類的例項化。
(2)抽象工廠:使用反射可以減少抽象工廠的子類。
採用反射技術可以簡化工廠**的複雜程度,在.net專案中,採用反射技術的工廠已經基本代替了工廠方法。
採用反射技術可以極大地簡化物件的生成,對以下設計模式的實現也有很大影響。
(1)命令模式:可以採用命令的型別名稱作為引數直接獲得命令的例項,並且可以動態執行命令。
(2)享元模式:採用反射技術例項化享元可以簡化享元工廠。
4.
反射的概述
反射的定義:審查元資料並收集關於它的型別資訊的能力。元資料(編譯以後的最基本資料單元)就是一大堆的表,當編譯程式集或者模組時,編譯器會建立乙個類 定義表,乙個字段定義表,和乙個方法定義表等,。system.reflection命名空間包含的幾個類,允許你反射(解析)這些元資料表的**
和反射相關的命名空間(我們就是通過這幾個命名空間訪問反射資訊):
system.reflection.memberinfo
system.reflection.eventinfo
system.reflection.fieldinfo
system.reflection.methodbase
system.reflection.constructorinfo
system.reflection.methodinfo
system.reflection.propertyinfo
system.type
system.reflection.assembly
反射的層次模型:
注:層次間都是一對多的關係
反射的作用:
1. 可以使用反射動態地建立型別的例項,將型別繫結到現有物件,或從現 有物件中獲取型別
2. 應用程式需要在執行時從某個特定的程式集中載入乙個特定的型別,以便實現某個任務時可以用到反射。
3. 反射主要應用與類庫,這些類庫需要知道乙個型別的定義,以便提供更多的功能。
2. loadfrom 方法:傳遞乙個程式集檔案的路徑名(包括副檔名),clr會載入您指定的這個程式集,傳遞的這個引數不能包含任何關於版本號的資訊,區域性,和公鑰資訊,如果在指定路徑找不到程式集丟擲異常。
利用反射獲取型別資訊
前面講完了關於程式集的反射,下面在講一下反射層次模型中的第三個層次,型別反射
乙個簡單的利用反射獲取型別資訊的例子:
其它幾種獲取type物件的方法:
1. system.type 引數為字串型別,該字串必須指定型別的完整名稱(包括其命名空間)
2. system.type 提供了兩個例項方法:getnestedtype,getnestedtypes
3. syetem.reflection.assembly 型別提供的例項方法是:gettype,gettypes,getexporedtypes
4. system.reflection.moudle 提供了這些例項方法:gettype,gettypes,findtypes
設定反射型別的成員
反射型別的成員就是反射層次模型中最下面的一層資料。我們可以通過type物件的getmembers 方法取得乙個型別的成員。如果我們使用的是不帶引數的getmembers,它只返回該型別的公共定義的靜態變數和例項成員,我們也可以通過使用帶引數的 getmembers通過引數設定來返回指定的型別成員。具體引數參考msdn 中system.reflection.bindingflags 列舉型別的詳細說明。
例如:
//設定需要返回的型別的成員內容
bindingflags bf=bingdingflags.declaredonly|bingdingflags.nonpublic|bingdingflags.public;
foreach (memberinfo mi int t.getmembers(bf))
通過反射建立型別的例項
通過反射可以獲取程式集的型別,我們就可以根據獲得的程式集型別來建立該型別新的例項,這也是前面提到的在執行時建立物件實現晚繫結的功能
我們可以通過下面的幾個方法實現:
如果你想要獲得乙個型別繼承的所有介面集合,可以呼叫type的findinte***ces getinte***ce或者getinte***ces。所有這些方法只能返回該型別直接繼承的介面,他們不會返回從乙個介面繼承下來的介面。要想返回 介面的基礎介面必須再次呼叫上述方法。
反射的效能:
使用反射來呼叫型別或者觸發方法,或者訪問乙個字段或者屬性時clr 需 要做更多的工作:校驗引數,檢查許可權等等,所以速度是非常慢的。所以盡量不要使用反射進行程式設計,對於打算編寫乙個動態構造型別(晚繫結)的應用程式,可以採取以下的幾種方式進行代替:
1. 通過類的繼承關係。讓該型別從乙個編譯時可知的基礎型別派生出來,在執行時生成該類 型的乙個例項,將對其的引用放到其基礎型別的乙個變數中,然後呼叫該基礎型別的虛方法。
2. 通過介面實現。在執行時,構建該型別的乙個例項,將對其的引用放到其介面型別的乙個變數中,然後呼叫該介面定義的虛方法。
3.通過委託實現。讓該型別實現乙個方法,其名稱和原型都與乙個在編譯時就已知的委託相符。在執行時先構造該型別的例項,然後在用該方法的物件及名稱構造 出該委託的例項,接著通過委託呼叫你想要的方法。這個方法相對與前面兩個方法所作的工作要多一些,效率更低一些 。
反射技術的應用 2
using system using system.collections.generic using system.linq using system.text using system.io using system.reflection 這個例子的應用場景是這樣的 我知道乙個屬性,像potit...
c 高階技術 反射
反射?難道是物理中光的反射?no no no 這個 反射 和物理一點關係都沒有!那什麼是反射呢?我個人的理解是 在程式中 動態的新增程式的功能 新增dll檔案 無需在源 中新增 從而實現為程式的功能 公升級 說的有些官方了 下面我舉幾個例子 我們都玩過遊戲 就拿我以前玩的qq飛車來說 遊戲廠商會隔一...
C 反射技術簡介
如果你要獲取到這個類的物件例項可以這麼做 以string類為例子 string str system.string string exp string activator.createinstance str 如果你要得到這個類的型別資訊可以這麼做 type exptype type.gettype...