反射原理-图文
①、了解反射前需要知道的結構關系。
反射(Reflection)是.NET中的重要機制,通過反射,可以在運行時獲得.NET中每一個類型(包括類、結構、委托、接口和枚舉等)的成員,包括方法、屬性、事件,以及構造函數等。還可以獲得每個成員的名稱、限定符和參數等。有了反射,即可對每一個類型了如指掌。如果獲得了構造函數的信息,即可直接創建對象,即使這個對象的類型在編譯時還不知道。?
我們在理解C#反射原理之前需要先搞明白幾個概念,以及他們之間的關系。
(1) ?AppDomain(Application Domain,簡稱App Domain):應用程序域,可以將其理解為一組程序集的邏輯容器 。
(2) ?Assembly:程序集類 。
(3) ?Module:模塊類? 。
(4) ?Type:使用反射得到類型信息的最核心的類? 。
他們之間是一種從屬關系,也就是說,一個AppDomain可以包含N個Assembly,一個Assembly可以包含N個Module,而一個Module可以包含N個Type,再者一個應用程序可以包含多個AppDomain,當程序跑起來后,對應的進程也可以創建多個appdomain,實現隔離,一個appdomain是不允許直接調用同一個進程中另一個appdomain的類型的,不同進程就更不用說啦。
?
程序代碼在編譯后生成可執行的應用,通過上圖我們首先要了解這種可執行應用程序的結構。?
應用程序結構分為應用程序域—程序集—模塊—類型—成員幾個層次,公共語言運行庫(CLR)加載器管理應用程序域,這種管理包括將每個程序集加載到相應的應用程序域以及控制每個程序集中類型層次結構的內存布局。?
程序集包含模塊,而模塊包含類型,類型又包含成員,反射則提供了封裝程序集、模塊和類型的對象。我們可以使用反射動態地創建類型的實例,將類型綁定到現有對象或從現有對象中獲取類型,然后調用類型的方法或訪問其字段和屬性。反射通常具有以下用途。?
(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命名空間包含的幾個類,允許你反射(解析)這些元數據表的代碼?
③、和反射相關的命名空間(我們就是通過這幾個命名空間訪問反射信息)
?? 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????
④、單個程序集的反射方法
我們常用的是Load方法:Load 方法帶有一個程序集標志并載入它,Load 將引起CLR把策略應用到程序集上,先后在全局程序集緩沖區,應用程序基目錄和私有路徑下面查找該程序集,如果找不到該程序集系統拋出異常 。
⑤、程序由.cs代碼開始運行的流程
C#是一個編譯型的語言,程序在運行C#之前,需要將.cs的文件編譯成電腦認識的含0和1的文件,即程序集文件(.dll),然后一個程序運行起來以后,有一個APPDomain,在這個APPDomain中放了我們用到的所有的“Assembly”,然后以“Assembly對象”方式加載到內存中運行。
⑥、如何獲取程序運行哪些程序集
通過如下代碼我們可以直觀的看到程序運行時都有哪些程序集。(前提要引用using system.Reflection)
Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();⑦、.cs代碼經過編譯后,在內存中運行時的狀態
程序集:*.exe,*.dll? ->加載到內存中就是Assembly對象
類:每個class,interface ->加載到內存中就是Type對象
類的成員:方法,字段,屬性,事件等 ->加載到內存中也有對應的對象。
⑧、反射動態創建實例
在程序運行時,動態獲取Assembly,Type,MethodInfo,PropertyInfo,FieldInfo,EventInfo的信息。之后動態創建類型實例,以及調用類型實例的成員。
⑨、反射的應用:
框架(Spring .net/.net MVC等)
【原理總結】
原理其實很簡單,.net所編寫的程序集包含兩個重要部分:IL(中間語言代碼)?和metadata(元數據)。我們編寫的代碼中不是有很多很多的類嗎,類有很多很多的成員,在編譯代碼的時候,元數據表就根據代碼把類的所有信息都記錄在了它里面(其實它就是一個數據結構,組織類的信息)。而反射的過程剛好相反,就是通過元數據里記錄的關于類的詳細信息找到該類的成員,并能使它“復活”(因為元數據里所記錄的信息足夠詳細,以致于可以根據metadata里面記錄的信息找到關于該類的IL code并加以利用)。
光的反射:
生活現象:
程序中代碼的反射:
上述講解中的概念解析
①、什么是AppDomain?
應用程序域:(Application Domain,簡稱App Domain)一組程序集的一個邏輯容器,進程中的一個邏輯分區。命名空間為system,程序集為mscorlib.dll。無法繼承此類。
當一個程序集被執行時,系統就會自動為其創建一個AppDomain,每個APPDomain屬于某個進程,一個進程內可以有多個APPDomain;每個APPDomain創建時都有個默認名稱,該名稱就是:程序集的名稱.exe。應用程序域是使用CreateDomain方法創建的,AppDomain實例用于加載和執行程序集(Assembly)。當不再使用AppDomain時,可以將其卸載。
AppDomain唯一的作用就是進行隔離。
具體功能:
隔離,一個AppDomain中的代碼創建的對象不能由另一個AppDomain中的代碼直接訪問。達到隔離應用程序的度效果。當然如果要訪問別的AppDomain中的內容,可以使用“按引用封送”或問者“按值封送”的語義。????
AppDomain可以卸載,但不能卸載單獨的程序集或類型,只能卸載整個應用程序域。從而卸載包含在該AppDomain中的所有程序集。
AppDomain可以單獨保護,AppDomain在創建后,會應用一個權限集,它決定了向這個AppDomain中運行的程序集授予的最大權限。從而保護宿主加載的代碼不被破壞。
可以單獨實施配置,內AppDomain在創建后,會關聯一組配置設置。這些設置主要影響CLR在AppDomain中加載程序集的方式。這些設置涉及搜索容路徑、版本重定向、卷影復制以及加載器優化。
②、什么是Assembly類?
Assembly是一個包含來程序的名稱,版本號,自我描述,文件關聯關系和文件位置等信息的一個集合。在.net框架中通過Assembly類來支持,該類位于System.Reflection下,物理位置位于:mscorlib.dll。
Assembly能干什么?
我們可以通過Assembly的信息來獲取程序的類,實例等編程需要用到的信息。
?
③、什么是CLR?
CLR(Comman Language Runtime)公共語言運行庫,它負責資源管理(內存分配和垃圾收集等),并保證應用和底層操作系統之間必要的分離。CLR和Java虛擬機一樣也是一個運行時環境,是一個可由多種編程語言使用的運行環境。CLR的核心功能包括:內存管理、程序集加載、安全性、異常處理和線程同步,可由面向CLR的所有語言使用。
④、什么是元數據?
元數據:元數據是一種二進制信息,用以對存儲在公共語言運行庫可移植可執行文件 (PE) 文件或存儲在內存中的程序進行描述。將您的代碼編譯為 PE 文件時,便會將元數據插入到該文件的一部分中,而將代碼轉換為 Microsoft 中間語言 (MSIL) 并將其插入到該文件的另一部分中。在模塊或程序集中定義和引用的每個類型和成員都將在元數據中進行說明。當執行代碼時,運行庫將元數據加載到內存中,并引用它來發現有關代碼的類、成員、繼承等信息。元數據以非特定語言的方式描述在代碼中定義的每一類型和成員。
每個元數據表都保留有關程序元素的信息。例如,一個元數據表說明代碼中的類,另一個元數據表說明字段等。如果您的代碼中有 10 個類,類表將有 10 行,每行一類。元數據表引用其他的表和堆。
參考鏈接:
https://www.cnblogs.com/w-wfy/p/7668818.html
https://blog.csdn.net/talent_jian/article/details/54837064
https://blog.csdn.net/yuhan61659/article/details/79498938
https://blog.csdn.net/CJB_King/article/details/80521481
總結
- 上一篇: 用低代码平台百数轻松实现返乡登记表制作
- 下一篇: 整除符号'|'(如 a|b)