.Net 中的反射(查看基本類型信息) - Part.2

摘:http://www.tracefact.net/CLR-and-Framework/Reflection-Part2.aspx

反射概述 和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(System.IO.Stream);

這時的使用有點像泛型,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 enum MemberTypes {
    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 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);
       }
    }

}

現在我們在 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.小結

本文涉及了反射的最基礎的內容,我們可以利用反射來自頂向下地查看程序集、模塊、類型、類型成員的信息。反射更強大、也更有意思的內容:遲綁定方法、動態創建類型以後會再講到。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章