.Net 中的反射(查看基本類(lèi)型信息) - Part.2
反射概述 和Type類(lèi)
1.反射的作用
簡(jiǎn)單來(lái)說(shuō),,反射提供這樣幾個(gè)能力:1,、查看和遍歷類(lèi)型(及其成員)的基本信息和程序集元數(shù)據(jù)(metadata);2,、遲綁定(Late-
Binding)方法和屬性,。3、動(dòng)態(tài)創(chuàng)建類(lèi)型實(shí)例(并可以動(dòng)態(tài)調(diào)用所創(chuàng)建的實(shí)例的方法,、字段,、屬性)。序章中,,我們所采用的那個(gè)例子,,只是反射的一個(gè)用
途:查看類(lèi)型成員信息。接下來(lái)的幾個(gè)章節(jié),,我們將依次介紹反射所提供的其他能力,。
2.獲取Type對(duì)象實(shí)例
反射的核心是Type類(lèi),這個(gè)類(lèi)封裝了關(guān)于對(duì)象的信息,,也是進(jìn)行反射的入口,。當(dāng)你獲得了關(guān)于類(lèi)型的Type對(duì)象后,就可以根據(jù)Type提供的屬性和
方法獲取這個(gè)類(lèi)型的一切信息(方法,、字段,、屬性、事件,、參數(shù),、構(gòu)造函數(shù)等)。我們開(kāi)始的第一步,,就是獲取關(guān)于類(lèi)型的Type實(shí)例,。獲取Type對(duì)象有兩種
形式,一種是獲取當(dāng)前加載程序集中的類(lèi)型(Runtime),,一種是獲取沒(méi)有加載的程序集的類(lèi)型,。
我們先考慮Runtime時(shí)的Type,一般來(lái)說(shuō)有三種獲取方法:
2.1使用Type類(lèi)提供的靜態(tài)方法GetType()
比如我們想要獲得Stream類(lèi)型的Type實(shí)例,,則可以這樣:
Type t = Type.GetType("System.IO.Stream");
txtOutput.Text = t.ToString();
注意到GetType方法接受字符串形式的類(lèi)型名稱(chēng),。
2.2 使用 typeof 操作符
也可以使用C# 提供的typeof 操作符來(lái)完成這一過(guò)程:
// 如果在頁(yè)首寫(xiě)入了using System.IO; 也可以直接用 typeof(Stream);
Type t = typeof(System.IO.Stream);
這時(shí)的使用有點(diǎn)像泛型,Stream就好像一個(gè)類(lèi)型參數(shù)一樣,,傳遞到typeof操作符中,。
2.3 通過(guò)類(lèi)型實(shí)例獲得Type對(duì)象
我們還可以通過(guò)類(lèi)型的實(shí)例來(lái)獲得:
String name = "Jimmy Zhang";
Type t = name.GetType();
使用這種方法時(shí)應(yīng)當(dāng)注意,盡管我們是通過(guò)變量(實(shí)例)去獲取Type對(duì)象,,但是Type對(duì)象不包含關(guān)于這個(gè)特定對(duì)象的信息,,仍是保存對(duì)象的類(lèi)型(String)的信息。
3.Type類(lèi)型 及 Reflection命名空間的組織結(jié)構(gòu)
到現(xiàn)在為止,我已經(jīng)多次提過(guò)Type封裝了類(lèi)型的信息,,那么這些類(lèi)型信息都包含什么內(nèi)容呢,?假設(shè)我們現(xiàn)在有一個(gè)類(lèi)型的實(shí)例,它的名字叫做 demo,,我們對(duì)它的信息一無(wú)所知,,并通過(guò)下面代碼獲取了對(duì)于它的Type實(shí)例:
// 前面某處的代碼實(shí)例化了demo對(duì)象
Type t = demo.GetType();
現(xiàn)在,我們期望 t 包含了關(guān)于 demo 的哪些信息呢,?
3.1 demo的類(lèi)型的基本信息
- 我們當(dāng)然首先想知道 demo 是什么類(lèi)型的,,也就是 demo 的類(lèi)型名稱(chēng),。
- 我們還想知道該類(lèi)型位于什么命名空間下,。
- 它的基類(lèi)型是什么,以及它在.Net運(yùn)行庫(kù)中的映射類(lèi)型,。
- 它是值類(lèi)型還是引用類(lèi)型,。
- 它是不是Public的。
- 它是枚舉,、是類(lèi),、是數(shù)組、還是接口,。
- 它是不是基礎(chǔ)類(lèi)型(int等),。
- 等等 ...
Type 提供了下面的屬性,用于獲取類(lèi)型的基本信息,,常用的有下面一些:
屬 性 |
說(shuō) 明 |
Name |
獲取類(lèi)型名稱(chēng) |
FullName |
類(lèi)型全名 |
Namespace |
命名空間名稱(chēng) |
BaseType |
獲取對(duì)于基類(lèi)的Type類(lèi)型的引用 |
UnderlyingSystemType |
在.Net中映射的類(lèi)型的引用 |
Attributes |
獲取TypeAttributes位標(biāo)記 |
IsValueType |
是否值類(lèi)型 |
IsByRef |
是否由引用傳遞 |
IsEnum |
是否枚舉 |
IsClass |
是否類(lèi) |
IsInterface |
是否接口 |
IsSealed |
是否密封類(lèi) |
IsPrimitive |
是否基類(lèi)型(比如int) |
IsAbstract |
是否抽象 |
IsPublic |
是否公開(kāi) |
IsNotPublic |
是否非公開(kāi) |
IsVisible |
是否程序集可見(jiàn) |
等等... |
|
3.2 demon的類(lèi)型的成員信息
- 我們可能還想知道它有哪些字段,。
- 有些什么屬性,以及關(guān)于這些屬性的信息,。
- 有哪些構(gòu)造函數(shù),。
- 有哪些方法,方法有哪些參數(shù),,有什么樣的返回值,。
- 包含哪些事件。
- 實(shí)現(xiàn)了哪些接口,。
- 我們還可以不加區(qū)分地獲得它的所有 以上成員,。
觀察上面的列表,就拿第一條來(lái)說(shuō),,我們想獲取類(lèi)型都有哪些字段,,以及這些字段的信息。而字段都包含哪些信息呢,?可能有字段的類(lèi)型,、字段的名稱(chēng)、字段
是否public、字段是否為const,、字段是否是read only 等等,,那么是不是應(yīng)該將字段的這些信息也封裝起來(lái)呢?
實(shí)際上,,.Net中提供了 FiledInfo 類(lèi)型,,它封裝了關(guān)于字段的相關(guān)信息。對(duì)照上面的列表,,類(lèi)似的還有
PropertyInfo類(lèi)型,、ConstructorInfo類(lèi)型、MethodInfo類(lèi)型,、EventInfo類(lèi)型,。而對(duì)于方法而言,對(duì)于它的參
數(shù),,也會(huì)有in參數(shù),,out參數(shù),參數(shù)類(lèi)型等信息,,類(lèi)似的,,在 System.Reflection
命名空間下,除了有上面的提到的那么多Info后綴結(jié)尾的類(lèi)型,,還有個(gè)ParameterInfo 類(lèi)型,,用于封裝方法的參數(shù)信息。
最后,,應(yīng)該注意到 Type 類(lèi)型,,以及所有的Info類(lèi)型均 繼承自 MemberInfo 類(lèi)型,MemberInfo類(lèi)型提供了獲取類(lèi)型基礎(chǔ)信息的能力,。
在VS2005中鍵入Type,,選中它,再按下F12跳轉(zhuǎn)到Type類(lèi)型的定義,,縱覽Type類(lèi)型的成員,,發(fā)現(xiàn)可以大致將屬性和方法分成這樣幾組:
- IsXXXX,比如 IsAbstract,,這組bool屬性用于說(shuō)明類(lèi)型的某個(gè)信息,。(前面的表格已經(jīng)列舉了一些。)
- GetXXXX(),,比如GetField(),,返回FieldInfo,這組方法用于獲取某個(gè)成員的信息,。
- GetXXXXs(),,比如GetFields(),,返回FieldInfo[],這組方法用戶獲取某些成員信息,。
- 還有其他的一些屬性和方法,,等后面遇到了再說(shuō)。
由于MemberInfo是一個(gè)基類(lèi),,當(dāng)我們獲得一個(gè)MemberInfo后,,我們并不知道它是PropertyInfo(封裝了屬性信息的對(duì)象)
還是FieldInfo(封裝了屬性信息的對(duì)象),所以,,有必要提供一個(gè)辦法可以讓我們加以判斷,,在Reflection
命名空間中,會(huì)遇到很多的位標(biāo)記,,這里先介紹第一個(gè)位標(biāo)記(本文管用[Flags]特性標(biāo)記的枚舉稱(chēng)為
位標(biāo)記),,MemberTypes,它用于標(biāo)記成員類(lèi)型,,可能的取值如下:
[Flags]
public enum MemberTypes {
Constructor = 1, // 該成員是一個(gè)構(gòu)造函數(shù)
Event = 2, // 該成員是一個(gè)事件
Field = 4, // 該成員是一個(gè)字段
Method = 8, // 該成員是一個(gè)方法
Property = 16, // 該成員是一個(gè)屬性
TypeInfo = 32, // 該成員是一種類(lèi)型
Custom = 64, // 自定義成員類(lèi)型
NestedType = 128, // 該成員是一個(gè)嵌套類(lèi)型
All = 191, // 指定所有成員類(lèi)型,。
}
反射程序集
在.Net中,,程序集是進(jìn)行部署,、版本控制的基本單位,它包含了相關(guān)的模塊和類(lèi)型,,我并不打算詳細(xì)地去說(shuō)明程序集及其構(gòu)成,,只是講述如何通過(guò)反射獲取程序集信息。
在System.Reflection命名空間下有一個(gè)Assembly類(lèi)型,,它代表了一個(gè)程序集,,并包含了關(guān)于程序集的信息。
在程序中加載程序集時(shí),,一般有這么幾個(gè)方法,,我們可以使用 Assembly類(lèi)型提供的靜態(tài)方法LoadFrom() 和 Load(),比如:
Assembly asm = Assembly.LoadFrom("Demo.dll");
或者
Assembly asm = Assembly.Load("Demo");
當(dāng)使用LoadFrom()方法的時(shí)候,,提供的是程序集的文件名,,當(dāng)將一個(gè)程序集添加到項(xiàng)目引用中以后,可以直接寫(xiě)“文件名.dll”,。如果想加載一個(gè)不屬于當(dāng)前項(xiàng)目的程序集,,則需要給出全路徑,比如:
Assembly asm = Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll");
使用Load()方法的時(shí)候,,只用提供程序集名稱(chēng)即可,,不需要提供程序集的后綴名。如果想獲得當(dāng)前程序集,,可以使用Assembly類(lèi)型的靜態(tài)方法 GetExecutingAssembly,,它返回包含當(dāng)前執(zhí)行的代碼的程序集(也就是當(dāng)前程序集),。
Assembly as = Assembly.GetExecutingAssembly();
在獲得一個(gè)Type類(lèi)型實(shí)例以后,我們還可以使用該實(shí)例的Assembly屬性來(lái)獲得其所在的程序集:
Type t = typeof(int)
Assembly asm = t.Assembly;
一個(gè)程序集可能有多個(gè)模塊(Module)組成,,每個(gè)模塊又可能包含很多的類(lèi)型,,但.Net的默認(rèn)編譯模式一個(gè)程序集只會(huì)包含一個(gè)模塊,我們現(xiàn)在看下 反射 提供了什么樣的能力讓我們獲取關(guān)于程序集的信息(只列出了部分常用的):
屬 性/方 法 |
說(shuō) 明 |
FullName |
程序集名稱(chēng) |
Location |
程序集的路徑 |
GetTypes() |
獲取程序集包含的全部類(lèi)型 |
GetType() |
獲取某個(gè)類(lèi)型 |
GetModules() |
獲取程序集包含的模塊 |
GetModule() |
獲取某個(gè)模塊 |
GetCustomAttributes() |
獲取自定義特性信息 |
NOTE:程序集和命名空間不存在必然聯(lián)系,,一個(gè)程序集可以包含多個(gè)命名空間,,同一個(gè)命名空間也可以分放在幾個(gè)程序集。
為了方便進(jìn)行我們后面的測(cè)試,,我們現(xiàn)在建立一個(gè)Windows控制臺(tái)應(yīng)用程序,,我給它起名叫SimpleExplore;然后再添加一個(gè)Demo類(lèi)
庫(kù)項(xiàng)目,,我們將來(lái)編寫(xiě)的代碼就用戶查看這個(gè)Demo項(xiàng)目集的類(lèi)型信息 或者
是對(duì)這個(gè)程序集中的類(lèi)型進(jìn)行遲綁定,。這個(gè)Demon項(xiàng)目只包含一個(gè)命名空間Demo,為了體現(xiàn)盡可能多的類(lèi)型同時(shí)又Keep Simple,,其代碼如下:
namespace Demo {
public abstract class BaseClass {
}
public struct DemoStruct { }
public delegate void DemoDelegate(Object sender, EventArgs e);
public enum DemoEnum {
terrible, bad, common=4, good, wonderful=8
}
public interface IDemoInterface {
void SayGreeting(string name);
}
public interface IDemoInterface2 {}
public sealed class DemoClass:BaseClass, IDemoInterface,IDemoInterface2 {
private string name;
public string city;
public readonly string title;
public const string text = "Const Field";
public event DemoDelegate myEvent;
public string Name {
private get { return name; }
set { name = value; }
}
public DemoClass() {
title = "Readonly Field";
}
public class NestedClass { }
public void SayGreeting(string name) {
Console.WriteLine("Morning :" + name);
}
}
}
現(xiàn)在我們?cè)?SimpleExplore項(xiàng)目中寫(xiě)一個(gè)方法AssemblyExplor(),,查看我們Demo項(xiàng)目生成的程序集Demo.dll定義的全部類(lèi)型:
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(" 類(lèi)型:" + t + "\n");
}
Console.WriteLine(sb.ToString());
}
然后,我們?cè)贛ain()方法中調(diào)用一下,,應(yīng)該可以看到這樣的輸出結(jié)果:
FullName(全名):Demo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Location(路徑):E:\MyApp\TypeExplorer\SimpleExplorer\bin\Debug\Demo.dll
模塊: Demo.dll
類(lèi)型:Demo.BaseClass
類(lèi)型:Demo.DemoStruct
類(lèi)型:Demo.DemoDelegate
類(lèi)型:Demo.DemoEnum
類(lèi)型:Demo.IDemoInterface
類(lèi)型:Demo.IDemoInterface2
類(lèi)型:Demo.DemoClass
類(lèi)型:Demo.DemoClass+NestedClass
反射基本類(lèi)型
這里說(shuō)反射基本類(lèi)型,,基本類(lèi)型是針對(duì) 泛型類(lèi)型 來(lái)說(shuō)的,因?yàn)?反射泛型
會(huì)更加復(fù)雜一些,。在前面的范例中,,我們獲得了程序集中的所有類(lèi)型,并循環(huán)打印了它們,,打印結(jié)果僅僅顯示出了類(lèi)型的全名,,而我們通常需要關(guān)于類(lèi)型更詳細(xì)的信
息,本節(jié)我們就來(lái)看看如何進(jìn)一步查看類(lèi)型信息,。
NOTE:因?yàn)橐粋€(gè)程序集包含很多類(lèi)型,,一個(gè)類(lèi)型包含很多成員(方法、屬性等),,一個(gè)成員又包含很多其他的信息,,所以如果我們從程序集層次開(kāi)始寫(xiě)代碼去獲取每個(gè)層級(jí)的信息,那么會(huì)嵌套很多的foreach語(yǔ)句,,為了閱讀方便,,我會(huì)去掉最外層的循環(huán)。
1.獲取基本信息
有了前面Type一節(jié)的介紹,,我想完成這里應(yīng)該只是打打字而已,,所以我直接寫(xiě)出代碼,如有必要,,會(huì)在注釋中加以說(shuō)明,。我們?cè)賹?xiě)一個(gè)方法TypeExplore,,用于獲取類(lèi)型的詳細(xì)信息(記得AssemblyExplore只獲取了類(lèi)型的名稱(chēng)):
public static void TypeExplore(Type t) {
StringBuilder sb = new StringBuilder();
sb.Append("名稱(chēng)信息:\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(基類(lèi)型): " + t.BaseType + "\n");
sb.Append("UnderlyingSystemType: " + t.UnderlyingSystemType + "\n");
sb.Append("\n類(lèi)型信息:\n");
sb.Append("Attributes(TypeAttributes位標(biāo)記): " + t.Attributes + "\n");
sb.Append("IsValueType(值類(lèi)型): " + t.IsValueType + "\n");
sb.Append("IsEnum(枚舉): " + t.IsEnum + "\n");
sb.Append("IsClass(類(lèi)): " + t.IsClass + "\n");
sb.Append("IsArray(數(shù)組): " + t.IsArray + "\n");
sb.Append("IsInterface(接口): " + t.IsInterface + "\n");
sb.Append("IsPointer(指針): " + t.IsPointer + "\n");
sb.Append("IsSealed(密封): " + t.IsSealed + "\n");
sb.Append("IsPrimitive(基類(lèi)型): " + t.IsPrimitive + "\n");
sb.Append("IsAbstract(抽象): " + t.IsAbstract + "\n");
sb.Append("IsPublic(公開(kāi)): " + t.IsPublic + "\n");
sb.Append("IsNotPublic(不公開(kāi)): " + t.IsNotPublic + "\n");
sb.Append("IsVisible: " + t.IsVisible + "\n");
sb.Append("IsByRef(由引用傳遞): " + t.IsByRef + "\n");
Console.WriteLine(sb.ToString());
}
然后,我們?cè)贛ain方法中輸入:
Type t = typeof(DemoClass);
TypeExplore(t);
會(huì)得到這樣的輸出:
名稱(chēng)信息:
Name: DemoClass
FullName: Demo.DemoClass
Namespace: Demo
其他信息:
BaseType(基類(lèi)型): Demo.BaseClass
UnderlyingSystemType: Demo.DemoClass
類(lèi)型信息:
Attributes(TypeAttributes位標(biāo)記): AutoLayout, AnsiClass, Class, Public, Sealed,
BeforeFieldInit
IsValueType(值類(lèi)型): False
IsEnum(枚舉): False
IsClass(類(lèi)): True
IsArray(數(shù)組): False
IsInterface(接口): False
IsPointer(指針): False
IsSealed(密封): True
IsPrimitive(基類(lèi)型): False
IsAbstract(抽象): False
IsPublic(公開(kāi)): True
IsNotPublic(不公開(kāi)): False
IsVisible: True
IsByRef(由引用傳遞): False
值得注意的是Attributes屬性,,它返回一個(gè)TypeAttributes位標(biāo)記,,這個(gè)標(biāo)記標(biāo)識(shí)了類(lèi)型的一些元信息,可以看到我們熟悉的Class,、Public,、Sealed。相應(yīng)的,,IsClass,、IsSealed、IsPublic等屬性也返回為T(mén)rue,。
2.成員信息 與 MemberInfo 類(lèi)型
我們先考慮一下對(duì)于一個(gè)類(lèi)型Type,,可能會(huì)包含什么類(lèi)型,常見(jiàn)的有字段,、屬性,、方法、構(gòu)造函數(shù),、接口,、嵌套類(lèi)型等。MemberInfo
類(lèi)代表著
Type的成員類(lèi)型,,值得注意的是Type類(lèi)本身又繼承自MemberInfo類(lèi),,理解起來(lái)并不困難,,因?yàn)橐粋€(gè)類(lèi)型經(jīng)常也是另一類(lèi)型的成員,。Type類(lèi)提
供 GetMembers()、GetMember(),、FindMember()等方法用于獲取某個(gè)成員類(lèi)型,。
我們?cè)偬砑右粋€(gè)方法 MemberExplore(),來(lái)查看一個(gè)類(lèi)型的所有成員類(lèi)型,。
public static void MemberExplore(Type t) {
StringBuilder sb = new StringBuilder();
MemberInfo[] memberInfo = t.GetMembers();
sb.Append("查看類(lèi)型 " + t.Name + "的成員信息:\n");
foreach (MemberInfo mi in memberInfo) {
sb.Append("成員:" + mi.ToString().PadRight(40) + " 類(lèi)型: " + mi.MemberType + "\n");
}
Console.WriteLine(sb.ToString());
}
然后我們?cè)贛ain方法中調(diào)用一下,。
MemberExplore(typeof(DemoClass));
產(chǎn)生的輸出如下:
查看類(lèi)型 DemoClass的成員信息:
--------------------------------------------------
成員:Void add_myEvent(Demo.DemoDelegate) 類(lèi)型: Method
成員:Void remove_myEvent(Demo.DemoDelegate) 類(lèi)型: Method
成員:System.String get_Name() 類(lèi)型: Method
成員:Void set_Name(System.String) 類(lèi)型: Method
成員:Void SayGreeting(System.String) 類(lèi)型: Method
成員:System.Type GetType() 類(lèi)型: Method
成員:System.String ToString() 類(lèi)型: Method
成員:Boolean Equals(System.Object) 類(lèi)型: Method
成員:Int32 GetHashCode() 類(lèi)型: Method
成員:Void .ctor() 類(lèi)型: Constructor
成員:System.String Name 類(lèi)型: Property
成員:Demo.DemoDelegate myEvent 類(lèi)型: Event
成員:System.String text 類(lèi)型: Field
成員:Demo.DemoClass+NestedClass 類(lèi)型: NestedType
我們使用了GetMembers()方法獲取了成員信息的一個(gè)數(shù)組,然后遍歷了數(shù)組,,打印了成員的名稱(chēng)和類(lèi)型,。如同我們所知道的:Name屬性在編
譯后成為了get_Name()和set_Name()兩個(gè)獨(dú)立的方法;myEvent事件的注冊(cè)(+=)和取消注冊(cè)(-=)分別成為了
add_myEvent()和remove_myEvent方法,。同時(shí),,我們發(fā)現(xiàn)私有(private)字段name
沒(méi)有被打印出來(lái),另外,,基類(lèi)System.Object的成員GetType()和Equals()也被打印了出來(lái),。
有的時(shí)候,,我們可能不希望查看基類(lèi)的成員,也可能希望查看私有的成員,,此時(shí)可以使用GetMembers()的重載方法,,傳入
BindingFlags
位標(biāo)記參數(shù)來(lái)完成。BindingFlags位標(biāo)記對(duì)如何獲取成員的方式進(jìn)行控制(也可以控制如何創(chuàng)建對(duì)象實(shí)例,,后面會(huì)說(shuō)明),。對(duì)于本例,如果我們想獲取
所有的公有,、私有,、靜態(tài)、實(shí)例 成員,,那么只需要這樣修改GetMembers()方法就可以了,。
MemberInfo[] memberInfo = t.GetMembers(
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly
);
此時(shí)的輸出如下:
查看類(lèi)型 DemoClass的成員信息:
--------------------------------------------------
成員:Void add_myEvent(Demo.DemoDelegate) 類(lèi)型: Method
成員:Void remove_myEvent(Demo.DemoDelegate) 類(lèi)型: Method
成員:System.String get_Name() 類(lèi)型: Method
成員:Void set_Name(System.String) 類(lèi)型: Method
成員:Void SayGreeting(System.String) 類(lèi)型: Method
成員:Void .ctor() 類(lèi)型: Constructor
成員:System.String Name 類(lèi)型: Property
成員:Demo.DemoDelegate myEvent 類(lèi)型: Event
成員:System.String name 類(lèi)型: Field
成員:Demo.DemoDelegate myEvent 類(lèi)型: Field
成員:System.String text 類(lèi)型: Field
成員:Demo.DemoClass+NestedClass 類(lèi)型: NestedType
可以看到,繼承自基類(lèi) System.Object 的方法都被過(guò)濾掉了,,同時(shí),,打印出了私有的 name, myEvent 等字段。
現(xiàn)在如果我們想要獲取所有的方法(Method),,那么我們可以使用 Type類(lèi)的FindMembers()方法:
MemberInfo[] memberInfo = t.FindMembers(
MemberTypes.Method, // 說(shuō)明查找的成員類(lèi)型為 Method
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly,
Type.FilterName,
"*"
);
Type.FilterName 返回一個(gè)MemberFilter類(lèi)型的委托,,它說(shuō)明按照方法名稱(chēng)進(jìn)行過(guò)濾,最后一個(gè)參數(shù)“*”,,說(shuō)明返回所有名稱(chēng)(如果使用“Get*”,,則會(huì)返回所有以Get開(kāi)頭的方法)。現(xiàn)在的輸出如下:
查看類(lèi)型 DemoClass的成員信息:
--------------------------------------------------
成員:Void add_myEvent(Demo.DemoDelegate) 類(lèi)型: Method
成員:Void remove_myEvent(Demo.DemoDelegate) 類(lèi)型: Method
成員:System.String get_Name() 類(lèi)型: Method
成員:Void set_Name(System.String) 類(lèi)型: Method
成員:Void SayGreeting(System.String) 類(lèi)型: Method
MemberInfo 類(lèi)有兩個(gè)屬性值得注意,,一個(gè)是DeclaringType,,一個(gè)是 ReflectedType,返回的都是Type類(lèi)型,。DeclaredType 返回的是聲明該成員的類(lèi)型,。比如說(shuō),回顧我們之前的一段代碼:
MemberInfo[] members = typeof(DemoClass).GetMembers();
它將返回所有的公有成員,,包括繼承自基類(lèi)的Equals()等方法,,對(duì)于Equals()方法來(lái)說(shuō),它的 DeclaringType
返回的是相當(dāng)于 typeof(Object) 的類(lèi)型實(shí)例,,因?yàn)樗窃?System.Object中被定義的,;而它的ReflectedType
返回的則是相當(dāng)于 typeof(DemoClass) 類(lèi)型實(shí)例,因?yàn)樗峭ㄟ^(guò) DemoClass 的類(lèi)型實(shí)例被獲取的,。
3.字段信息 與 FieldInfo類(lèi)型
如同我們之前所說(shuō),,MemberInfo 是一個(gè)基類(lèi),它包含的是類(lèi)型的各種成員都公有的一組信息,。實(shí)際上,,對(duì)于字段,、屬性、方法,、事件
等類(lèi)型成員來(lái)說(shuō),,它們包含的信息顯然都是不一樣的,所以,,.Net 中提供了 FiledInfo
類(lèi)型來(lái)封裝字段的信息,,它繼承自MemberInfo。
如果我們希望獲取一個(gè)類(lèi)型的所有字段,,可以使用 GetFileds()方法,。我們?cè)俅翁砑右粋€(gè)方法FieldExplore():
public static void FieldExplore(Type t) {
StringBuilder sb = new StringBuilder();
FieldInfo[] fields = t.GetFields();
sb.Append("查看類(lèi)型 " + t.Name + "的字段信息:\n");
sb.Append(String.Empty.PadLeft(50, '-') + "\n");
foreach (FieldInfo fi in fields) {
sb.Append("名稱(chēng):" + fi.Name + "\n");
sb.Append("類(lèi)型:" + fi.FieldType + "\n");
sb.Append("屬性:" + fi.Attributes + "\n\n");
}
Console.WriteLine(sb.ToString());
}
產(chǎn)生的輸出如下:
查看類(lèi)型 DemoClass的字段信息:
--------------------------------------------------
名稱(chēng):city
類(lèi)型:System.String
屬性:Public
名稱(chēng):title
類(lèi)型:System.String
屬性:Public, InitOnly
名稱(chēng):text
類(lèi)型:System.String
屬性:Public, Static, Literal, HasDefault
值得一提的是fi.FieldType
屬性,它返回一個(gè)FieldAttributes位標(biāo)記,,這個(gè)位標(biāo)記包含了字段的屬性信息,。對(duì)比我們之前定義的DemoClass類(lèi),可以看到,,對(duì)于
title 字段,,它的屬性是public,
InitOnly;對(duì)于Const類(lèi)型的text字段,,它的屬性為Public,Static,Literal,,HasDefault,由此也可以看出,,
聲明一個(gè)const類(lèi)型的變量,,它默認(rèn)就是靜態(tài)static的,同時(shí),,由于我們給了它初始值,,所以位標(biāo)記中也包括HasDefault。
針對(duì)于FieldType位標(biāo)記,,F(xiàn)iledInfo 類(lèi)提供了一組返回為bool類(lèi)型的屬性,,來(lái)說(shuō)明字段的信息,常用的有:IsPublic, IsStatic, IsInitOnly, IsLiteral, IsPrivate 等,。
如果我們想要獲取私有字段信息,依然可以使用重載了的GetFields[]方法,,傳入BindingFlags參數(shù),,和上面的類(lèi)似,這里就不重復(fù)了,。
4.屬性信息 與 PropertyInfo 類(lèi)型
和字段類(lèi)似,,也可以通過(guò) GetProperty()方法,獲取類(lèi)型的所有屬性信息,。
public static void PropertyExplore(Type t) {
StringBuilder sb = new StringBuilder();
sb.Append("查看類(lèi)型 " + t.Name + "的屬性信息:\n");
sb.Append(String.Empty.PadLeft(50, '-') + "\n");
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties) {
sb.Append("名稱(chēng):" + pi.Name + "\n");
sb.Append("類(lèi)型:" + pi.PropertyType + "\n");
sb.Append("可讀:" + pi.CanRead + "\n");
sb.Append("可寫(xiě):" + pi.CanWrite +"\n");
sb.Append("屬性:" + pi.Attributes +"\n");
}
Console.WriteLine(sb.ToString());
}
輸出如下:
查看類(lèi)型 DemoClass的屬性信息:
--------------------------------------------------
名稱(chēng):Name
類(lèi)型:System.String
可讀:True
可寫(xiě):True
屬性:None
從前面的章節(jié)可以看到,,Name屬性會(huì)在編譯后生成Get_Name()和Set_Name()兩個(gè)方法,,那么,應(yīng)該可以利用反射獲取這兩個(gè)方法,。
PropertyInfo類(lèi)的GetGetMethod()和GetSetMethod()可以完成這個(gè)工作,,它返回一個(gè)MethodInfo對(duì)象,封裝
了關(guān)于方法的信息,,我們會(huì)在后面看到,。
5.方法信息 與 MethodInfo 類(lèi)型
與前面的類(lèi)似,我們依然可以編寫(xiě)代碼來(lái)查看類(lèi)型的方法信息,。
public static void MethodExplore(Type t) {
StringBuilder sb = new StringBuilder();
sb.Append("查看類(lèi)型 " + t.Name + "的方法信息:\n");
sb.Append(String.Empty.PadLeft(50, '-') + "\n");
MethodInfo[] methods = t.GetMethods();
foreach (MethodInfo method in methods) {
sb.Append("名稱(chēng):" + method.Name +"\n");
sb.Append("簽名:" + method.ToString() + "\n");
sb.Append("屬性:" + method.Attributes + "\n");
sb.Append("返回值類(lèi)型:" + method.ReturnType + "\n\n");
}
Console.WriteLine(sb.ToString());
}
與前面類(lèi)似,,MethodInfo
類(lèi)也有一個(gè)Attributes屬性,它返回一個(gè)MethodAttribute,,MethodAttribute
位標(biāo)記標(biāo)明了方法的一些屬性,,常見(jiàn)的比如Abstract, Static, Virtual,Public, Private 等。
與前面不同的是,,Method可以具有參數(shù) 和 返回值,,MethodInfo 類(lèi)提供了 GetParameters() 方法獲取
參數(shù)對(duì)象的數(shù)組,方法的參數(shù)都封裝在了 ParameterInfo 類(lèi)型中,。查看ParameterInfo類(lèi)型的方法與前面類(lèi)似,,這里就不再闡述了。
6. ConstructorInfo類(lèi)型,、EventInfo 類(lèi)型
從名稱(chēng)就可以看出來(lái),,這兩個(gè)類(lèi)型封裝了類(lèi)型 的構(gòu)造函數(shù) 和 事件信息,大家都是聰明人,,查看這些類(lèi)型與之前的方法類(lèi)似,,這里就不再重復(fù)了。
7.小結(jié)
本文涉及了反射的最基礎(chǔ)的內(nèi)容,,我們可以利用反射來(lái)自頂向下地查看程序集,、模塊、類(lèi)型,、類(lèi)型成員的信息,。反射更強(qiáng)大、也更有意思的內(nèi)容:遲綁定方法,、動(dòng)態(tài)創(chuàng)建類(lèi)型以后會(huì)再講到,。
轉(zhuǎn)載地址:http://www./CLR-and-Framework/Reflection-Part2.aspx