首頁 後端開發 C#.Net教程 C#學習之Reflection

C#學習之Reflection

Dec 20, 2016 pm 05:18 PM
c

1、什麼是反射: 
Reflection,中文翻譯為反射。
這是.Net中獲取運行時類型資訊的方式 ,.Net的應用程式由幾個部分: '組件(Assembly)'、'模組(Module)'、'類型(class)'組成,而反射提供一種編程的方式,讓程式設計師可以在程式運行期獲得這幾個組成部分的相關資訊。

反射的概述 

反射的定義:審查元資料並收集關於它的類型資訊的能力 。元資料(編譯以後最基本的資料單 元)就是一大堆的表,當編譯組件或模組時,編譯器會建立一個類別定義表,一個欄位定義表,和一個方法定義表等。 System.reflection命名 空間包含的幾個類,讓你可以反射(解析)這些元資料表的程式碼。


2、反射的具體用途:

(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來了解參數的名稱、資料型別、是輸入參數或輸出參數,以及參數在方法簽章中的位置等。


3、與反射相關的命名空間:


System.Reflection.Assembly

System.Reflection.MemberInfo
System.Reflection.Re.InfoSystem.Reflection.MemberInfo
System.Reflection.Re.id.S. ConstructorInfo
System.Reflection.MethodInfo
System.Reflection.PropertyInfo
System.Type


4、反射的層次模型:

: 1. 可以使用反射動態地建立類型的實例,將類型綁定到現有對象,或從現有對像中取得類型
2. 應用程式需要在執行時間從某個特定的程式集中載入一個特定的類型,以便在實現某個任務時可以用到反射。
3. 反射主要應用與類別庫,這些類別庫需要知道一個類型的定義,以便提供更多的功能。

應用要點:

1. 現實應用程式中很少有應用程式需要使用反射類型
2. 使用反射動態綁定需要犧牲效能
3. 有些元資料資訊是不能透過反射取得的
4. 某些反射類型是專門為那些CLR開發編譯器的開發使用的,所以你要意識到不是所有的反射類型都是適合每個人的。

6、反射的實際應用:

反射appDomain 的程序集 

static void Main
{
// 透過GetAssemblies 呼叫appDomain的所有程序集
foreach (Assembly assem in Appdomain.currentDomain.GetAssemblies(Assembly assem in Appdomain.currentDomain.GetAssemblies(GetAssembly)> reflector.ReflectOnAssembly(assem)
}
}

說明:呼叫AppDomain 物件的GetAssemblies 方法將傳回由System.Reflection.Assembly元素組成的陣列。

反射單一組件 

我們可以顯示的呼叫其中的一個組件,system.reflecton.assembly 類型提供了以下三種方法:

1. Load 方法:極力推薦的一種方法,Load 方法帶有一個組件標誌並載入它,Load 將引起CLR把策略應用到組件上,先後在全域組件緩衝區,應用程式基目錄和私有路徑下面查找該程序集,如果找不到該程序集系統拋出異常。
2. LoadFrom 方法:傳遞一個組件檔案的路徑名(包括副檔名),CLR會載入您指定的這個程式集,傳遞的這個參數不能包含任何關於版本號的信息,區域性,和公鑰訊息, 如果在指定路徑找不到組件拋出例外。
3. LoadWithPartialName:永遠不要使用這個方法,因為應用程式無法確定再在載入的組件的版本。此方法的唯一用途是幫助那些在.Net框 架的測試環節使用.net 框架提供的某種行為的客戶,這個方法將最終被拋棄不用。
注意:system.AppDomain 也提供了一種Load 方法,他和Assembly的靜態Load 方法不一樣,AppDomain的load 方法是一種實例方法,返回的是一個對程序集的引用,Assembly的靜態Load 方發將程式集按值封裝發回給發出呼叫的AppDomain.盡量避免使用AppDomain的load 方法

利用反射獲取類型資訊 

一個簡單的利用反射獲取類型資訊的例子:

using system;
using sytem. reflection;
class reflecting
{
static void Main(string[]args)
{
reflecting reflect=new reflecting();// 定義一個新的自身類別
//呼叫一個reflecting.exe大約assembly.loadfrom(“reflecting.exe”)
reflect.getreflectioninfo(myAssembly);// 取得反射資訊
}
// 定義一個取得反射內容的方法
void getreflectioninfo(assembly mhyasse)> myassemby.Gettypes();//取得類型
foreach (type type in typearr)//針對每個類型取得詳細資訊
{
//取得類型的結構資訊
constructorinfo[] myconstructors=type.GetConstructors;
//取得類型的欄位資訊
fieldinfo[] myfields=type.GetFiedls()
//取得方法資訊
MethodInfo myMethodInfo=type.GetMethods();
// 取得屬性資訊
propertyInfo[] myproperties=type.Gpperties=type.取得事件資訊
EventInfo[] Myevents=type.GetEvents;
}
}
}

其它幾種取得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 (MInfoInfomimi int temberm; mi.membertype) //輸出指定的類型成員
}

透過反射建立類型的實例 

透過反射可以取得組件的類型,我們就可以根據所獲得的組件類型來建立該類型新的實例,這也是前面提到的在運行時創建物件實現晚綁定的功能。我們可以透過下面的幾個方法來實現:

1. System.Activator 的CreateInstance方法。該方法傳回新物件的引用。
2. System.Activator 的createInstanceFrom 與上一個方法類似,不過需要指定類型及其組件。
3. System.Appdomain 的方法:createInstance,CreateInstanceAndUnwrap,CreateInstranceFrom和 CreateInstraceFromAndUnwrap
4. System.type 的InvokeMember實例方法:這個方法傳回一個與傳入參數相符的建構函數,並且建構這個型別。
5. System.reflection.constructinfo 的Invoke實例方法

反射類型的介面 

如果你想要取得一個類型繼承的所有介面集合,可以呼叫 Type的FindInterfaces GetInterface或 GetInterfaces。所有這些方法只能返回該類型直接繼承的接口,他們不會返回從一個接口繼承下來的接口。要返回介面的基礎介面必須再次呼叫上述方法。

反射的性能 

反射時CLR要做更多的工作:校驗參數,檢查權限等等,速度是非常慢的。 盡量不要使用反射進行編程,對於打算編寫一個動態構造類型(晚綁定)的應用程序,可採取以下幾種方式進行代替:

1.透過類別的繼承關係。讓該類型從一個編譯時可知的基礎類型派生出來,在運行時產生該類型的一個實例,將對其的引用放到其基礎類型的一個變數中,然後調用該基礎類型的虛擬方法。
2.透過接口實現。在運行時,建構該類型的一個實例,將對其的引用放到其介面類型的變數中,然後呼叫該介面定義的虛擬方法。
3.透過委託實現。讓該類型實作一個方法,其名稱和原型都與一個在編譯時就已知的委託相符。在執行時先建構該類型的實例,然後在用該方法的物件及名稱建構出該委託的實例,接著透過委託呼叫你想要的方法。這個方法相對與前面兩個方法所做的工作要多一些,效率也更低一些。

使用注意事項:

1、跨程序集的反射

在開發中,經常會遇到這種情況,在A.dll中需要反射B.dll中的類型,如果稍不注意,就會產生運行時錯誤。關於跨程式集的反射,記住兩點:
(1)如果使用typeof,編譯能通過,則跨程式集的反射一定可以正常運作。可以說,typeof是支援強型別的。例如

Type supType = typeof(EnterpriseServerBase.DataAccess.IDBAccesser) ;

如果目前組件沒有新增對EnterpriseServerBase.dll的引用,則編譯會報錯。

(2)如果使用Type.GetType,情況就複雜些,這是因為Type.GetType是非強類型的。 Type.GetType的參數是一個 string,當string表示的目標類型不在目前程式集中,則執行時Type.GetType會傳回null。解決的方法是:先載入目標組件,然後再使用Assembly.GetType方法。如

Assembly asmb = Assembly.LoadFrom("EnterpriseServerBase.dll") ;
Type supType = asmb.GetType("EnterpriseServerBase.DataAccess.IDBAccesser") ;

注意,使用類型. EnterpriseServerBase.dll的引用,Type.GetType("EnterpriseServerBase.DataAccess.IDBAccesser")也會傳回null,這是因為Type.GetType只會在目前程式集中進行型別搜尋。

2、反射時判斷一個方法的回傳型別是否為void

Type serviceType = typeof(T);
MethodInfo methodInfo = serviceType.GetMethod(methodName);
即可。


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

C語言中的常數是什麼,可以舉例嗎? C語言中的常數是什麼,可以舉例嗎? Aug 28, 2023 pm 10:45 PM

常量也稱為變量,一旦定義,其值在程式執行期間​​就不會改變。因此,我們可以將變數宣告為引用固定值的常數。它也被稱為文字。必須使用Const關鍵字來定義常數。語法C程式語言中使用的常數語法如下-consttypeVariableName;(or)consttype*VariableName;不同類型的常數在C程式語言中使用的不同類型的常數如下所示:整數常數-例如:1,0,34, 4567浮點數常數-例如:0.0,156.89,23.456八進制和十六進制常數-例如:十六進制:0x2a,0xaa..八進制

VSCode和VS C++IntelliSense無法運作或拾取函式庫 VSCode和VS C++IntelliSense無法運作或拾取函式庫 Feb 29, 2024 pm 01:28 PM

VS程式碼和VisualStudioC++IntelliSense可能無法拾取函式庫,尤其是在處理大型專案時。當我們將滑鼠懸停在#Include<wx/wx.h>上時,我們看到了錯誤訊息「CannotOpen來源檔案'string.h'」(依賴於「wx/wx.h」),有時,自動完成功能無法回應。在這篇文章中,我們將看到如果VSCode和VSC++IntelliSense不能工作或不能提取庫,你可以做些什麼。為什麼我的智能感知不能在C++中運作?處理大型檔案時,IntelliSense有時

修復Xbox錯誤代碼8C230002 修復Xbox錯誤代碼8C230002 Feb 27, 2024 pm 03:55 PM

您是否因為錯誤代碼8C230002而無法在Xbox上購買或觀看內容?一些用戶在嘗試購買或在其控制台上觀看內容時不斷收到此錯誤。抱歉,Xbox服務出現問題。稍後再試。有關此問題的協助,請造訪www.xbox.com/errorhelp。狀態代碼:8C230002這種錯誤代碼通常是由於暫時的伺服器或網路問題引起的。但是,還有可能是由於帳戶的隱私設定或家長控制等其他原因,這些可能會阻止您購買或觀看特定內容。修正Xbox錯誤代碼8C230002如果您嘗試在Xbox控制台上觀看或購買內容時收到錯誤代碼8C

遞歸程式在C++中找到陣列的最小和最大元素 遞歸程式在C++中找到陣列的最小和最大元素 Aug 31, 2023 pm 07:37 PM

我們以整數數組Arr[]作為輸入。目標是使用遞歸方法在陣列中找到最大和最小的元素。由於我們使用遞歸,我們將遍歷整個數組,直到達到長度=1,然後返回A[0],這形成了基本情況。否則,將當前元素與當前最小或最大值進行比較,並透過遞歸更新其值以供後續元素使用。讓我們來看看這個的各種輸入輸出場景−輸入 −Arr={12,67,99,76,32};輸出 −數組中的最大值:99解釋 &mi

中國東方航空宣布C919客機即將投入實際運營 中國東方航空宣布C919客機即將投入實際運營 May 28, 2023 pm 11:43 PM

5月25日消息,中國東方航空在業績說明會上揭露了關於C919客機的最新進展。據公司表示,與中國商飛簽署的C919採購協議已於2021年3月正式生效,其中首架C919飛機已於2022年底交付。預計不久之後,該飛機將正式投入實際運作。東方航空將以上海為主要基地進行C919的商業運營,並計劃在2022年和2023年引進總共5架C919客機。該公司表示,未來的引進計畫將根據實際營運狀況和航線網路規劃來決定。據小編了解,C919是中國具有完全自主智慧財產權的全球新一代單通道幹線客機,符合國際通行的適航標準。該

C++程式列印數字的螺旋圖案 C++程式列印數字的螺旋圖案 Sep 05, 2023 pm 06:25 PM

以不同格式顯示數字是學習基本編碼問題之一。不同的編碼概念,如條件語句和迴圈語句。有不同的程式中,我們使用特殊字元(如星號)來列印三角形或正方形。在本文中,我們將以螺旋形式列印數字,就像C++中的正方形一樣。我們將行數n作為輸入,然後從左上角開始移向右側,然後向下,然後向左,然後向上,然後再次向右,以此類推等等。螺旋圖案與數字123456724252627282982340414243309223948494431102138474645321120373635343312191817161514

C語言中的void關鍵字的作用 C語言中的void關鍵字的作用 Feb 19, 2024 pm 11:33 PM

C中的void是一個特殊的關鍵字,用來表示空類型,也就是指沒有具體類型的資料。在C語言中,void通常用於以下三個方面。函數傳回類型為void在C語言中,函數可以有不同的回傳類型,例如int、float、char等。然而,如果函數不傳回任何值,則可以將傳回類型設為void。這意味著函數執行完畢後,並不傳回具體的數值。例如:voidhelloWorld()

23 年來首次,C# 獲得了 TIOBE 2023 年度程式語言獎 23 年來首次,C# 獲得了 TIOBE 2023 年度程式語言獎 Jan 11, 2024 pm 04:45 PM

根據TIOBE程式設計社群指數,該指數是衡量程式語言受歡迎程度的標準之一,透過收集來自全球工程師、課程、供應商和搜尋引擎的數據進行評估。 2024年1月TIOBE指數於近日發布,同時官方公佈了2023年程式語言排名,C#榮獲TIOBE2023年度程式語言,這是23年來C#首次拿下這項榮譽。 TIOBE官方新聞稿稱,C#已經穩居前10名長達20多年,如今它正在追趕四大語言,成為一年內漲幅最大的程式語言(+1.43%),當之無愧地獲得了該獎項。排名第二的是Scratch(+0.83%)和Fortran(+0

See all articles