.Net 中的反射(檢視基本型別資訊)
反射概述 和Type類
1.反射的作用
簡單來說,反射提供這樣幾個能力:1、檢視和遍歷型別(及其成員)的基本資訊和程式集元資料(metadata);2、遲繫結(Late-Binding)方法和屬性。3、動態建立型別例項(並可以動態呼叫所建立的例項的方法、欄位、屬性)。序章中,我們所採用的那個例子,只是反射的一個用途:檢視型別成員資訊。接下來的幾個章節,我們將依次介紹反射所提供的其他能力。
2.獲取Type物件例項
反射的核心是Type類,這個類封裝了關於物件的資訊,也是進行反射的入口。當你獲得了關於型別的Type物件後,就可以根據Type提供的屬性和方法獲取這個型別的一切資訊(方法、欄位、屬性、事件、引數、建構函式等)。我們開始的第一步,就是獲取關於型別的Type例項。獲取Type物件有兩種形式,一種是獲取當前載入程式集中的型別(Runtime),一種是獲取沒有載入的程式集的型別。
我們先考慮Runtime時的Type,一般來說有三種獲取方法:
2.1使用Type類提供的靜態方法GetType()
比如我們想要獲得Stream型別的Type例項,則可以這樣:
Type t = Type.GetType("System.IO.Stream");
txtOutput.Text = t.ToString();
注意到GetType方法接受字串形式的型別名稱。
2.2 使用 typeof 操作符
也可以使用C# 提供的typeof 操作符來完成這一過程:
// 如果在頁首寫入了using System.IO; 也可以直接用
typeof(Stream);
Type t = typeof
這時的使用有點像泛型,Stream就好像一個型別引數一樣,傳遞到typeof操作符中。
2.3 通過型別例項獲得Type物件
我們還可以通過型別的例項來獲得:
String name ="Jimmy Zhang";
Type t = name.GetType();
使用這種方法時應當注意,儘管我們是通過變數(例項)去獲取Type物件,但是Type物件不包含關於這個特定物件的資訊,仍是儲存物件的型別(String)的資訊。
3.Type型別 及 Reflection名稱空間的組織結構
到現在為止,我已經多次提過Type封裝了型別的資訊,那麼這些型別資訊都包含什麼內容呢?假設我們現在有一個型別的例項,它的名字叫做 demo,我們對它的資訊一無所知,並通過下面程式碼獲取了對於它的Type例項:
// 前面某處的程式碼例項化了demo物件
Type t = demo.GetType();
現在,我們期望 t 包含了關於 demo 的哪些資訊呢?
3.1 demo的型別的基本資訊
- 我們當然首先想知道 demo 是什麼型別的,也就是 demo 的型別名稱。
- 我們還想知道該型別位於什麼名稱空間下。
- 它的基型別是什麼,以及它在.Net執行庫中的對映型別。
- 它是值型別還是引用型別。
- 它是不是Public的。
- 它是列舉、是類、是陣列、還是介面。
- 它是不是基礎型別(int等)。
- 等等 ...
Type 提供了下面的屬性,用於獲取型別的基本資訊,常用的有下面一些:
屬 性 | 說 明 |
Name | 獲取型別名稱 |
FullName | 型別全名 |
Namespace | 名稱空間名稱 |
BaseType | 獲取對於基類的Type型別的引用 |
UnderlyingSystemType | 在.Net中對映的型別的引用 |
Attributes | 獲取TypeAttributes位標記 |
IsValueType | 是否值型別 |
IsByRef | 是否由引用傳遞 |
IsEnum | 是否列舉 |
IsClass | 是否類 |
IsInterface | 是否介面 |
IsSealed | 是否密封類 |
IsPrimitive | 是否基型別(比如int) |
IsAbstract | 是否抽象 |
IsPublic | 是否公開 |
IsNotPublic | 是否非公開 |
IsVisible | 是否程式集可見 |
等等... |
3.2 demon的型別的成員資訊
- 我們可能還想知道它有哪些欄位。
- 有些什麼屬性,以及關於這些屬性的資訊。
- 有哪些建構函式。
- 有哪些方法,方法有哪些引數,有什麼樣的返回值。
- 包含哪些事件。
- 實現了哪些介面。
- 我們還可以不加區分地獲得它的所有 以上成員。
觀察上面的列表,就拿第一條來說,我們想獲取型別都有哪些欄位,以及這些欄位的資訊。而欄位都包含哪些資訊呢?可能有欄位的型別、欄位的名稱、欄位是否public、欄位是否為const、欄位是否是read only 等等,那麼是不是應該將欄位的這些資訊也封裝起來呢?
實際上,.Net中提供了 FiledInfo 型別,它封裝了關於欄位的相關資訊。對照上面的列表,類似的還有 PropertyInfo型別、ConstructorInfo型別、MethodInfo型別、EventInfo型別。而對於方法而言,對於它的引數,也會有in引數,out引數,引數型別等資訊,類似的,在 System.Reflection 名稱空間下,除了有上面的提到的那麼多Info字尾結尾的型別,還有個ParameterInfo 型別,用於封裝方法的引數資訊。
最後,應該注意到 Type 型別,以及所有的Info型別均 繼承自 MemberInfo 型別,MemberInfo型別提供了獲取型別基礎資訊的能力。
在VS2005中鍵入Type,選中它,再按下F12跳轉到Type型別的定義,縱覽Type型別的成員,發現可以大致將屬性和方法分成這樣幾組:
- IsXXXX,比如 IsAbstract,這組bool屬性用於說明型別的某個資訊。(前面的表格已經列舉了一些。)
- GetXXXX(),比如GetField(),返回FieldInfo,這組方法用於獲取某個成員的資訊。
- GetXXXXs(),比如GetFields(),返回FieldInfo[],這組方法使用者獲取某些成員資訊。
- 還有其他的一些屬性和方法,等後面遇到了再說。
由於MemberInfo是一個基類,當我們獲得一個MemberInfo後,我們並不知道它是PropertyInfo(封裝了屬性資訊的物件)還是FieldInfo(封裝了屬性資訊的物件),所以,有必要提供一個辦法可以讓我們加以判斷,在Reflection 名稱空間中,會遇到很多的位標記,這裡先介紹第一個位標記(本文管用[Flags]特性標記的列舉稱為 位標記),MemberTypes,它用於標記成員型別,可能的取值如下:
[Flags]
public enumMemberTypes {
Constructor = 1, // 該成員是一個建構函式
Event = 2, // 該成員是一個事件
Field = 4, // 該成員是一個欄位
Method = 8, // 該成員是一個方法
Property = 16, // 該成員是一個屬性
TypeInfo = 32, // 該成員是一種型別
Custom = 64, // 自定義成員型別
NestedType = 128, // 該成員是一個巢狀型別
All = 191, // 指定所有成員型別。
}
反射程式集
在.Net中,程式集是進行部署、版本控制的基本單位,它包含了相關的模組和型別,我並不打算詳細地去說明程式集及其構成,只是講述如何通過反射獲取程式集資訊。
在System.Reflection名稱空間下有一個Assembly型別,它代表了一個程式集,幷包含了關於程式集的資訊。
在程式中載入程式集時,一般有這麼幾個方法,我們可以使用 Assembly型別提供的靜態方法LoadFrom() 和 Load(),比如:
Assembly asm = Assembly.LoadFrom("Demo.dll");
或者
Assembly asm = Assembly.Load("Demo");
當使用LoadFrom()方法的時候,提供的是程式集的檔名,當將一個程式集新增到專案引用中以後,可以直接寫“檔名.dll”。如果想載入一個不屬於當前專案的程式集,則需要給出全路徑,比如:
Assembly asm = Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll");
使用Load()方法的時候,只用提供程式集名稱即可,不需要提供程式集的字尾名。如果想獲得當前程式集,可以使用Assembly型別的靜態方法 GetExecutingAssembly,它返回包含當前執行的程式碼的程式集(也就是當前程式集)。
Assembly as = Assembly.GetExecutingAssembly();
在獲得一個Type型別例項以後,我們還可以使用該例項的Assembly屬性來獲得其所在的程式集:
Type t = typeof(int)
Assembly asm = t.Assembly;
一個程式集可能有多個模組(Module)組成,每個模組又可能包含很多的型別,但.Net的預設編譯模式一個程式集只會包含一個模組,我們現在看下 反射 提供了什麼樣的能力讓我們獲取關於程式集的資訊(只列出了部分常用的):
屬 性/方 法 | 說 明 |
FullName | 程式集名稱 |
Location | 程式集的路徑 |
GetTypes() | 獲取程式集包含的全部型別 |
GetType() | 獲取某個型別 |
GetModules() | 獲取程式集包含的模組 |
GetModule() | 獲取某個模組 |
GetCustomAttributes() | 獲取自定義特性資訊 |
NOTE:程式集和名稱空間不存在必然聯絡,一個程式集可以包含多個名稱空間,同一個名稱空間也可以分放在幾個程式集。
為了方便進行我們後面的測試,我們現在建立一個Windows控制檯應用程式,我給它起名叫SimpleExplore;然後再新增一個Demo類庫專案,我們將來編寫的程式碼就使用者檢視這個Demo專案集的型別資訊 或者 是對這個程式集中的型別進行遲繫結。這個Demon專案只包含一個名稱空間Demo,為了體現儘可能多的型別同時又Keep Simple,其程式碼如下:
namespace Demo {
public abstractclass
BaseClass {
}
public structDemoStruct { }
public delegatevoid DemoDelegate(Object sender, EventArgs e);
public enumDemoEnum {
terrible, bad, common=4, good, wonderful=8
}
public interfaceIDemoInterface {
void SayGreeting(string name);
}
public interfaceIDemoInterface2 {}
public sealedclass
DemoClass:BaseClass, IDemoInterface,IDemoInterface2 {
private string name;
public string city;
public readonlystring title;
public conststring text ="Const Field";
public eventDemoDelegate myEvent;
public string Name {
private get {
return name; }
set { name = value; }
}
public DemoClass() {
title = "Readonly Field";
}
public classNestedClass { }
public void SayGreeting(string name) {
Console.WriteLine("Morning :" + name);
}
}
}
現在我們在 SimpleExplore專案中寫一個方法AssemblyExplor(),檢視我們Demo專案生成的程式集Demo.dll定義的全部型別:
public static void AssemblyExplore() {
StringBuilder sb = new StringBuilder();
Assembly asm = Assembly.Load("Demo");
sb.Append("FullName(全名):" + asm.FullName + "\n");
sb.Append("Location(路徑):" + asm.Location + "\n");
Type[] types = asm.GetTypes();
foreach (Type t in types) {
sb.Append(" 型別:" + t + "\n");
}
Console.WriteLine(sb.ToString());
}
然後,我們在Main()方法中呼叫一下,應該可以看到這樣的輸出結果:
FullName(全名):Demo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Location(路徑):E:\MyApp\TypeExplorer\SimpleExplorer\bin\Debug\Demo.dll
模組: Demo.dll
型別:Demo.BaseClass
型別:Demo.DemoStruct
型別:Demo.DemoDelegate
型別:Demo.DemoEnum
型別:Demo.IDemoInterface
型別:Demo.IDemoInterface2
型別:Demo.DemoClass
型別:Demo.DemoClass+NestedClass
反射基本型別
這裡說反射基本型別,基本型別是針對 泛型型別 來說的,因為 反射泛型 會更加複雜一些。在前面的範例中,我們獲得了程式集中的所有型別,並迴圈列印了它們,列印結果僅僅顯示出了型別的全名,而我們通常需要關於型別更詳細的資訊,本節我們就來看看如何進一步檢視型別資訊。
NOTE:因為一個程式集包含很多型別,一個型別包含很多成員(方法、屬性等),一個成員又包含很多其他的資訊,所以如果我們從程式集層次開始寫程式碼去獲取每個層級的資訊,那麼會巢狀很多的foreach語句,為了閱讀方便,我會去掉最外層的迴圈。
1.獲取基本資訊
有了前面Type一節的介紹,我想完成這裡應該只是打打字而已,所以我直接寫出程式碼,如有必要,會在註釋中加以說明。我們再寫一個方法TypeExplore,用於獲取型別的詳細資訊(記得AssemblyExplore只獲取了型別的名稱):
public
static void TypeExplore(Type t) {
StringBuilder sb =
new StringBuilder();
sb.Append("名稱資訊:\n");
sb.Append("Name: " + t.Name + "\n");
sb.Append("FullName: " + t.FullName + "\n");
sb.Append("Namespace: " + t.Namespace + "\n");
sb.Append("\n其他資訊:\n");
sb.Append("BaseType(基型別): " + t.BaseType + "\n");
sb.Append("UnderlyingSystemType: " + t.UnderlyingSystemType + "\n");
sb.Append("\n型別資訊:\n");
sb.Append("Attributes(TypeAttributes位標記): " + t.Attributes + "\n");
sb.Append("IsValueType(值型別): " + t.IsValueType + "\n");
sb.Append("IsEnum(列舉): " + t.IsEnum + "\n");
sb.Append("IsClass(類): " + t.IsClass + "\n");
sb.Append("IsArray(陣列): " + t.IsArray + "\n");
sb.Append("IsInterface(介面): " + t.IsInterface + "\n");
sb.Append("IsPointer(指標): " + t.IsPointer + "\n");
sb.Append("IsSealed(密封): " + t.IsSealed + "\n");
sb.Append("IsPrimitive(基型別): " + t.IsPrimitive + "\n");
sb.Append("IsAbstract(抽象): " + t.IsAbstract + "\n");
sb.Append("IsPublic(公開): " + t.IsPublic + "\n");
sb.Append("IsNotPublic(不公開): " + t.IsNotPublic + "\n");
sb.Append("IsVisible: " + t.IsVisible + "\n");
sb.Append("IsByRef(由引用傳遞): " + t.IsByRef + "\n");
Console.WriteLine(sb.ToString());
}
然後,我們在Main方法中輸入:
Type t = typeof(DemoClass);
TypeExplore(t);
會得到這樣的輸出:
名稱資訊:
Name: DemoClass
FullName: Demo.DemoClass
Namespace: Demo
其他資訊:
BaseType(基型別): Demo.BaseClass
UnderlyingSystemType: Demo.DemoClass
型別資訊:
Attributes(TypeAttributes位標記): AutoLayout, AnsiClass, Class, Public, Sealed,
BeforeFieldInit
IsValueType(值型別): False
IsEnum(列舉): False
IsClass(類): True
IsArray(陣列): False
IsInterface(介面): False
IsPointer(指標): False
IsSealed(密封): True
IsPrimitive(基型別): False
IsAbstract(抽象): False
IsPublic(公開): True
IsNotPublic(不公開): False
IsVisible: True
IsByRef(由引用傳遞): False
值得注意的是Attributes屬性,它返回一個TypeAttributes位標記,這個標記標識了型別的一些元資訊,可以看到我們熟悉的Class、Public、Sealed。相應的,IsClass、IsSealed、IsPublic等屬性也返回為True。
2.成員資訊 與 MemberInfo 型別
我們先考慮一下對於一個型別Type,可能會包含什麼型別,常見的有欄位、屬性、方法、建構函式、介面、巢狀型別等。MemberInfo 類代表著 Type的成員型別,值得注意的是Type類本身又繼承自MemberInfo類,理解起來並不困難,因為一個型別經常也是另一型別的成員。Type類提供 GetMembers()、GetMember()、FindMember()等方法用於獲取某個成員型別。
我們再新增一個方法 MemberExplore(),來檢視一個型別的所有成員型別。
public
static void MemberExplore(Type t) {
StringBuilder sb =
new StringBuilder();
MemberInfo[] memberInfo = t.GetMembers();
sb.Append("檢視型別 " + t.Name + "的成員資訊:\n");
foreach (MemberInfo mi in memberInfo) {
sb.Append("成員:" + mi.ToString().PadRight(40) + " 型別: " + mi.MemberType + "\n");
}
Console.WriteLine(sb.ToString());
}
然後我們在Main方法中呼叫一下。
MemberExplore(typeof(DemoClass));
產生的輸出如下:
檢視型別 DemoClass的成員資訊:
--------------------------------------------------
成員:Void add_myEvent(Demo.DemoDelegate) 型別: Method
成員:Void remove_myEvent(Demo.DemoDelegate) 型別: Method
成員:System.String get_Name() 型別: Method
成員:Void set_Name(System.String) 型別: Method
成員:Void SayGreeting(System.String) 型別: Method
成員:System.Type GetType() 型別: Method
成員:System.String ToString() 型別: Method
成員:Boolean Equals(System.Object) 型別: Method
成員:Int32 GetHashCode() 型別: Method
成員:Void .ctor() 型別: Constructor
成員:System.String Name 型別: Property
成員:Demo.DemoDelegate myEvent 型別: Event
成員:System.String text 型別: Field
成員:Demo.DemoClass+NestedClass 型別: NestedType
我們使用了GetMembers()方法獲取了成員資訊的一個數組,然後遍歷了陣列,列印了成員的名稱和型別。如同我們所知道的:Name屬性在編譯後成為了get_Name()和set_Name()兩個獨立的方法;myEvent事件的註冊(+=)和取消註冊(-=)分別成為了add_myEvent()和remove_myEvent方法。同時,我們發現私有(private)欄位name 沒有被打印出來,另外,基類System.Object的成員GetType()和Equals()也被列印了出來。
有的時候,我們可能不希望檢視基類的成員,也可能希望檢視私有的成員,此時可以使用GetMembers()的過載方法,傳入BindingFlags 位標記引數來完成。BindingFlags位標記對如何獲取成員的方式進行控制(也可以控制如何建立物件例項,後面會說明)。對於本例,如果我們想獲取所有的公有、私有、靜態、例項 成員,那麼只需要這樣修改GetMembers()方法就可以了。
MemberInfo[] memberInfo = t.GetMembers(
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly
);
此時的輸出如下:
檢視型別 DemoClass的成員資訊:
--------------------------------------------------
成員:Void add_myEvent(Demo.DemoDelegate) 型別: Method
成員:Void remove_myEvent(Demo.DemoDelegate) 型別: Method
成員:System.String get_Name() 型別: Method
成員:Void set_Name(System.String) 型別: Method
成員:Void SayGreeting(System.String) 型別: Method
成員:Void .ctor() 型別: Constructor
成員:System.String Name 型別: Property
成員:Demo.DemoDelegate myEvent 型別: Event
成員:System.String name 型別: Field
成員:Demo.DemoDelegate myEvent 型別: Field
成員:System.String text 型別: Field
成員:Demo.DemoClass+NestedClass 型別: NestedType
可以看到,繼承自基類 System.Object 的方法都被過濾掉了,同時,打印出了私有的 name, myEvent 等欄位。
現在如果我們想要獲取所有的方法(Method),那麼我們可以使用 Type類的FindMembers()方法:
MemberInfo[] memberInfo = t.FindMembers(
MemberTypes.Method, // 說明查詢的成員型別為 Method
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly,
Type.FilterName,
"*"
);
Type.FilterName 返回一個MemberFilter型別的委託,它說明按照方法名稱進行過濾,最後一個引數“*”,說明返回所有名稱(如果使用“Get*”,則會返回所有以Get開頭的方法)。現在的輸出如下:
檢視型別 DemoClass的成員資訊:
--------------------------------------------------
成員:Void add_myEvent(Demo.DemoDelegate) 型別: Method
成員:Void remove_myEvent(Demo.DemoDelegate) 型別: Method
成員:System.String get_Name() 型別: Method
成員:Void set_Name(System.String) 型別: Method
成員:Void SayGreeting(System.String) 型別: Method
MemberInfo 類有兩個屬性值得注意,一個是DeclaringType,一個是 ReflectedType,返回的都是Type型別。DeclaredType 返回的是宣告該成員的型別。比如說,回顧我們之前的一段程式碼:
MemberInfo[] members = typeof(DemoClass).GetMembers();
它將返回所有的公有成員,包括繼承自基類的Equals()等方法,對於Equals()方法來說,它的 DeclaringType 返回的是相當於 typeof(Object) 的型別例項,因為它是在 System.Object中被定義的;而它的ReflectedType 返回的則是相當於 typeof(DemoClass) 型別例項,因為它是通過 DemoClass 的型別例項被獲取的。
3.欄位資訊 與 FieldInfo型別
如同我們之前所說,MemberInfo 是一個基類,它包含的是型別的各種成員都公有的一組資訊。實際上,對於欄位、屬性、方法、事件 等型別成員來說,它們包含的資訊顯然都是不一樣的,所以,.Net 中提供了 FiledInfo 型別來封裝欄位的資訊,它繼承自MemberInfo。
如果我們希望獲取一個型別的所有欄位,可以使用 GetFileds()方法。我們再次新增一個方法FieldExplore():
public
static void FieldExplore(Type t) {
StringBuilder sb =
new StringBuilder();
FieldInfo[] fields = t.GetFields();
sb.Append("檢視型別 " + t.Name + "的欄位資訊:\n");
sb.Append(String.Empty.PadLeft(50, '-') +
"\n");
foreach (FieldInfo fi in fields) {
sb.Append("名稱:" + fi.Name + "\n");
sb.Append("型別:" + fi.FieldType + "\n");
sb.Append("屬性:" + fi.Attributes + "\n\n");
}
Console.WriteLine(sb.ToString());
}
產生的輸出如下:
檢視型別 DemoClass的欄位資訊:
--------------------------------------------------
名稱:city
型別:System.String
屬性:Public
名稱:title
型別:System.String
屬性:Public, InitOnly
名稱:text
型別:System.String
屬性:Public, Static, Literal, HasDefault
值得一提的是fi.FieldType 屬性,它返回一個FieldAttributes位標記,這個位標記包含了欄位的屬性資訊。對比我們之前定義的DemoClass類,可以看到,對於title 欄位,它的屬性是public, InitOnly;對於Const型別的text欄位,它的屬性為Public,Static,Literal,HasDefault,由此也可以看出,宣告一個const型別的變數,它預設就是靜態static的,同時,由於我們給了它初始值,所以位標記中也包括HasDefault。
針對於FieldType位標記,FiledInfo 類提供了一組返回為bool型別的屬性,來說明欄位的資訊,常用的有:IsPublic, IsStatic, IsInitOnly, IsLiteral, IsPrivate 等。
如果我們想要獲取私有欄位資訊,依然可以使用過載了的GetFields[]方法,傳入BindingFlags引數,和上面的類似,這裡就不重複了。
4.屬性資訊 與 PropertyInfo 型別
和欄位類似,也可以通過 GetProperty()方法,獲取型別的所有屬性資訊。
public
static void PropertyExplore(Type t) {
StringBuilder sb =
new StringBuilder();
sb.Append("檢視型別 " + t.Name + "的屬性資訊:\n");
sb.Append(String.Empty.PadLeft(50, '-') +
"\n");
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties) {
sb.Append("名稱:" + pi.Name + "\n");
sb.Append("型別:" + pi.PropertyType + "\n");
sb.Append("可讀:" + pi.CanRead + "\n");
sb.Append("可寫:" + pi.CanWrite +"\n");
sb.Append("屬性:" + pi.Attributes +"\n");
}
Console.WriteLine(sb.ToString());
}
輸出如下:
檢視型別 DemoClass的屬性資訊:
--------------------------------------------------
名稱:Name
型別:System.String
可讀:True
可寫:True
屬性:None
從前面的章節可以看到,Name屬性會在編譯後生成Get_Name()和Set_Name()兩個方法,那麼,應該可以利用反射獲取這兩個方法。PropertyInfo類的GetGetMethod()和GetSetMethod()可以完成這個工作,它返回一個MethodInfo物件,封裝了關於方法的資訊,我們會在後面看到。
5.方法資訊 與 MethodInfo 型別
與前面的類似,我們依然可以編寫程式碼來檢視型別的方法資訊。
public
static void MethodExplore(Type t) {
StringBuilder sb =
new StringBuilder();
sb.Append("檢視型別 " + t.Name + "的方法資訊:\n");
sb.Append(String.Empty.PadLeft(50, '-') +
"\n");
MethodInfo[] methods = t.GetMethods();
foreach (MethodInfo method in methods) {
sb.Append("名稱:" + method.Name +"\n");
sb.Append("簽名:" + method.ToString() + "\n");
sb.Append("屬性:" + method.Attributes + "\n");
sb.Append("返回值型別:" + method.ReturnType + "\n\n");
}
Console.WriteLine(sb.ToString());
}
與前面類似,MethodInfo 類也有一個Attributes屬性,它返回一個MethodAttribute,MethodAttribute 位標記標明瞭方法的一些屬性,常見的比如Abstract, Static, Virtual,Public, Private 等。
與前面不同的是,Method可以具有引數 和 返回值,MethodInfo 類提供了 GetParameters() 方法獲取 引數物件的陣列,方法的引數都封裝在了 ParameterInfo 型別中。檢視ParameterInfo型別的方法與前面類似,這裡就不再闡述了。
6. ConstructorInfo型別、EventInfo 型別
從名稱就可以看出來,這兩個型別封裝了型別 的建構函式 和 事件資訊,大家都是聰明人,檢視這些型別與之前的方法類似,這裡就不再重複了。
7.小結
本文涉及了反射的最基礎的內容,我們可以利用反射來自頂向下地檢視程式集、模組、型別、型別成員的資訊。反射更強大、也更有意思的內容:遲繫結方法、動態建立型別以後會再講到。
轉自:http://www.tracefact.net/CLR-and-Framework/Reflection-Part2.aspx