小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

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

 googo 2011-07-13
.Net 中的反射(查看基本類型信息) - Part.2(轉(zhuǎn)載)
2008年03月22日 星期六 13:39

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

反射概述 和Type類

1.反射的作用

簡單來說,反射提供這樣幾個能力:1、查看和遍歷類型(及其成員)的基本信息和程序集元數(shù)據(jù)(metadata);2、遲綁定(Late- Binding)方法和屬性。3、動態(tài)創(chuàng)建類型實例(并可以動態(tài)調(diào)用所創(chuàng)建的實例的方法、字段、屬性)。序章中,我們所采用的那個例子,只是反射的一個用 途:查看類型成員信息。接下來的幾個章節(jié),我們將依次介紹反射所提供的其他能力。

2.獲取Type對象實例

反射的核心是Type類,這個類封裝了關(guān)于對象的信息,也是進(jìn)行反射的入口。當(dāng)你獲得了關(guān)于類型的Type對象后,就可以根據(jù)Type提供的屬性和 方法獲取這個類型的一切信息(方法、字段、屬性、事件、參數(shù)、構(gòu)造函數(shù)等)。我們開始的第一步,就是獲取關(guān)于類型的Type實例。獲取Type對象有兩種 形式,一種是獲取當(dāng)前加載程序集中的類型(Runtime),一種是獲取沒有加載的程序集的類型。

我們先考慮Runtime時的Type,一般來說有三種獲取方法:

2.1使用Type類提供的靜態(tài)方法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就好像一個類型參數(shù)一樣,傳遞到typeof操作符中。

2.3 通過類型實例獲得Type對象

我們還可以通過類型的實例來獲得:

String name = "Jimmy Zhang";
Type t = name.GetType();

使用這種方法時應(yīng)當(dāng)注意,盡管我們是通過變量(實例)去獲取Type對象,但是Type對象不包含關(guān)于這個特定對象的信息,仍是保存對象的類型(String)的信息。

3.Type類型 及 Reflection命名空間的組織結(jié)構(gòu)

到現(xiàn)在為止,我已經(jīng)多次提過Type封裝了類型的信息,那么這些類型信息都包含什么內(nèi)容呢?假設(shè)我們現(xiàn)在有一個類型的實例,它的名字叫做 demo,我們對它的信息一無所知,并通過下面代碼獲取了對于它的Type實例:

// 前面某處的代碼實例化了demo對象
Type t = demo.GetType();

現(xiàn)在,我們期望 t 包含了關(guān)于 demo 的哪些信息呢?

3.1 demo的類型的基本信息

  • 我們當(dāng)然首先想知道 demo 是什么類型的,也就是 demo 的類型名稱。
  • 我們還想知道該類型位于什么命名空間下。
  • 它的基類型是什么,以及它在.Net運行庫中的映射類型。
  • 它是值類型還是引用類型。
  • 它是不是Public的。
  • 它是枚舉、是類、是數(shù)組、還是接口。
  • 它是不是基礎(chǔ)類型(int等)。
  • 等等 ...

Type 提供了下面的屬性,用于獲取類型的基本信息,常用的有下面一些:

屬 性 說 明
Name 獲取類型名稱
FullName 類型全名
Namespace 命名空間名稱
BaseType 獲取對于基類的Type類型的引用
UnderlyingSystemType 在.Net中映射的類型的引用
Attributes 獲取TypeAttributes位標(biāo)記
IsValueType 是否值類型
IsByRef 是否由引用傳遞
IsEnum 是否枚舉
IsClass 是否類
IsInterface 是否接口
IsSealed 是否密封類
IsPrimitive 是否基類型(比如int)
IsAbstract 是否抽象
IsPublic 是否公開
IsNotPublic 是否非公開
IsVisible 是否程序集可見
等等...

3.2 demon的類型的成員信息  

  • 我們可能還想知道它有哪些字段。
  • 有些什么屬性,以及關(guān)于這些屬性的信息。
  • 有哪些構(gòu)造函數(shù)。
  • 有哪些方法,方法有哪些參數(shù),有什么樣的返回值。
  • 包含哪些事件。
  • 實現(xiàn)了哪些接口。
  • 我們還可以不加區(qū)分地獲得它的所有 以上成員。

觀察上面的列表,就拿第一條來說,我們想獲取類型都有哪些字段,以及這些字段的信息。而字段都包含哪些信息呢?可能有字段的類型、字段的名稱、字段 是否public、字段是否為const、字段是否是read only 等等,那么是不是應(yīng)該將字段的這些信息也封裝起來呢?

實際上,.Net中提供了 FiledInfo 類型,它封裝了關(guān)于字段的相關(guān)信息。對照上面的列表,類似的還有 PropertyInfo類型、ConstructorInfo類型、MethodInfo類型、EventInfo類型。而對于方法而言,對于它的參 數(shù),也會有in參數(shù),out參數(shù),參數(shù)類型等信息,類似的,在 System.Reflection 命名空間下,除了有上面的提到的那么多Info后綴結(jié)尾的類型,還有個ParameterInfo 類型,用于封裝方法的參數(shù)信息。

最后,應(yīng)該注意到 Type 類型,以及所有的Info類型均 繼承自 MemberInfo 類型,MemberInfo類型提供了獲取類型基礎(chǔ)信息的能力。

在VS2005中鍵入Type,選中它,再按下F12跳轉(zhuǎn)到Type類型的定義,縱覽Type類型的成員,發(fā)現(xiàn)可以大致將屬性和方法分成這樣幾組:

  • IsXXXX,比如 IsAbstract,這組bool屬性用于說明類型的某個信息。(前面的表格已經(jīng)列舉了一些。)
  • GetXXXX(),比如GetField(),返回FieldInfo,這組方法用于獲取某個成員的信息。
  • GetXXXXs(),比如GetFields(),返回FieldInfo[],這組方法用戶獲取某些成員信息。
  • 還有其他的一些屬性和方法,等后面遇到了再說。

由于MemberInfo是一個基類,當(dāng)我們獲得一個MemberInfo后,我們并不知道它是PropertyInfo(封裝了屬性信息的對象) 還是FieldInfo(封裝了屬性信息的對象),所以,有必要提供一個辦法可以讓我們加以判斷,在Reflection 命名空間中,會遇到很多的位標(biāo)記,這里先介紹第一個位標(biāo)記(本文管用[Flags]特性標(biāo)記的枚舉稱為 位標(biāo)記),MemberTypes,它用于標(biāo)記成員類型,可能的取值如下:

[Flags]
public enum MemberTypes {
    Constructor = 1, // 該成員是一個構(gòu)造函數(shù)
    Event = 2,        // 該成員是一個事件
    Field = 4,        // 該成員是一個字段
    Method = 8,           // 該成員是一個方法
    Property = 16,    // 該成員是一個屬性
    TypeInfo = 32,    // 該成員是一種類型
    Custom = 64,      // 自定義成員類型
    NestedType = 128, // 該成員是一個嵌套類型
    All = 191,        // 指定所有成員類型。
}

反射程序集

在.Net中,程序集是進(jìn)行部署、版本控制的基本單位,它包含了相關(guān)的模塊和類型,我并不打算詳細(xì)地去說明程序集及其構(gòu)成,只是講述如何通過反射獲取程序集信息。

在System.Reflection命名空間下有一個Assembly類型,它代表了一個程序集,并包含了關(guān)于程序集的信息。

在程序中加載程序集時,一般有這么幾個方法,我們可以使用 Assembly類型提供的靜態(tài)方法LoadFrom() 和 Load(),比如:

Assembly asm = Assembly.LoadFrom("Demo.dll");

或者

Assembly asm = Assembly.Load("Demo");

當(dāng)使用LoadFrom()方法的時候,提供的是程序集的文件名,當(dāng)將一個程序集添加到項目引用中以后,可以直接寫“文件名.dll”。如果想加載一個不屬于當(dāng)前項目的程序集,則需要給出全路徑,比如:

Assembly asm = Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll");

使用Load()方法的時候,只用提供程序集名稱即可,不需要提供程序集的后綴名。如果想獲得當(dāng)前程序集,可以使用Assembly類型的靜態(tài)方法 GetExecutingAssembly,它返回包含當(dāng)前執(zhí)行的代碼的程序集(也就是當(dāng)前程序集)。

Assembly as = Assembly.GetExecutingAssembly();

在獲得一個Type類型實例以后,我們還可以使用該實例的Assembly屬性來獲得其所在的程序集:

Type t = typeof(int)
Assembly asm = t.Assembly;

一個程序集可能有多個模塊(Module)組成,每個模塊又可能包含很多的類型,但.Net的默認(rèn)編譯模式一個程序集只會包含一個模塊,我們現(xiàn)在看下 反射 提供了什么樣的能力讓我們獲取關(guān)于程序集的信息(只列出了部分常用的):

屬 性/方 法 說 明
FullName 程序集名稱
Location 程序集的路徑
GetTypes() 獲取程序集包含的全部類型
GetType() 獲取某個類型
GetModules() 獲取程序集包含的模塊
GetModule() 獲取某個模塊
GetCustomAttributes() 獲取自定義特性信息

NOTE:程序集和命名空間不存在必然聯(lián)系,一個程序集可以包含多個命名空間,同一個命名空間也可以分放在幾個程序集。

為了方便進(jìn)行我們后面的測試,我們現(xiàn)在建立一個Windows控制臺應(yīng)用程序,我給它起名叫SimpleExplore;然后再添加一個Demo類 庫項目,我們將來編寫的代碼就用戶查看這個Demo項目集的類型信息 或者 是對這個程序集中的類型進(jìn)行遲綁定。這個Demon項目只包含一個命名空間Demo,為了體現(xiàn)盡可能多的類型同時又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)在我們在 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()方法中調(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
   類型:Demo.BaseClass
   類型:Demo.DemoStruct
   類型:Demo.DemoDelegate
   類型:Demo.DemoEnum
   類型:Demo.IDemoInterface
   類型:Demo.IDemoInterface2
   類型:Demo.DemoClass
   類型:Demo.DemoClass+NestedClass

反射基本類型

這里說反射基本類型,基本類型是針對 泛型類型 來說的,因為 反射泛型 會更加復(fù)雜一些。在前面的范例中,我們獲得了程序集中的所有類型,并循環(huán)打印了它們,打印結(jié)果僅僅顯示出了類型的全名,而我們通常需要關(guān)于類型更詳細(xì)的信 息,本節(jié)我們就來看看如何進(jìn)一步查看類型信息。

NOTE:因為一個程序集包含很多類型,一個類型包含很多成員(方法、屬性等),一個成員又包含很多其他的信息,所以如果我們從程序集層次開始寫代碼去獲取每個層級的信息,那么會嵌套很多的foreach語句,為了閱讀方便,我會去掉最外層的循環(huán)。

1.獲取基本信息

有了前面Type一節(jié)的介紹,我想完成這里應(yīng)該只是打打字而已,所以我直接寫出代碼,如有必要,會在注釋中加以說明。我們再寫一個方法TypeExplore,用于獲取類型的詳細(xì)信息(記得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位標(biāo)記): " + t.Attributes + "\n");
    sb.Append("IsValueType(值類型): " + t.IsValueType + "\n");
    sb.Append("IsEnum(枚舉): " + t.IsEnum + "\n");
    sb.Append("IsClass(類): " + 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(基類型): " + 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位標(biāo)記): AutoLayout, AnsiClass, Class, Public, Sealed,
BeforeFieldInit
IsValueType(值類型): False
IsEnum(枚舉): False
IsClass(類): True
IsArray(數(shù)組): False
IsInterface(接口): False
IsPointer(指針): False
IsSealed(密封): True
IsPrimitive(基類型): False
IsAbstract(抽象): False
IsPublic(公開): True
IsNotPublic(不公開): False
IsVisible: True
IsByRef(由引用傳遞): False

值得注意的是Attributes屬性,它返回一個TypeAttributes位標(biāo)記,這個標(biāo)記標(biāo)識了類型的一些元信息,可以看到我們熟悉的Class、Public、Sealed。相應(yīng)的,IsClass、IsSealed、IsPublic等屬性也返回為True。

2.成員信息 與 MemberInfo 類型

我們先考慮一下對于一個類型Type,可能會包含什么類型,常見的有字段、屬性、方法、構(gòu)造函數(shù)、接口、嵌套類型等。MemberInfo 類代表著 Type的成員類型,值得注意的是Type類本身又繼承自MemberInfo類,理解起來并不困難,因為一個類型經(jīng)常也是另一類型的成員。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方法中調(diào)用一下。

MemberExplore(typeof(DemoClass));

產(chǎn)生的輸出如下:

查看類型 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()方法獲取了成員信息的一個數(shù)組,然后遍歷了數(shù)組,打印了成員的名稱和類型。如同我們所知道的:Name屬性在編 譯后成為了get_Name()和set_Name()兩個獨立的方法;myEvent事件的注冊(+=)和取消注冊(-=)分別成為了 add_myEvent()和remove_myEvent方法。同時,我們發(fā)現(xiàn)私有(private)字段name 沒有被打印出來,另外,基類System.Object的成員GetType()和Equals()也被打印了出來。

有的時候,我們可能不希望查看基類的成員,也可能希望查看私有的成員,此時可以使用GetMembers()的重載方法,傳入 BindingFlags 位標(biāo)記參數(shù)來完成。BindingFlags位標(biāo)記對如何獲取成員的方式進(jìn)行控制(也可以控制如何創(chuàng)建對象實例,后面會說明)。對于本例,如果我們想獲取 所有的公有、私有、靜態(tài)、實例 成員,那么只需要這樣修改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 等字段。

現(xiàn)在如果我們想要獲取所有的方法(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類型的委托,它說明按照方法名稱進(jìn)行過濾,最后一個參數(shù)“*”,說明返回所有名稱(如果使用“Get*”,則會返回所有以Get開頭的方法)?,F(xiàn)在的輸出如下:

查看類型 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 返回的是相當(dāng)于 typeof(Object) 的類型實例,因為它是在 System.Object中被定義的;而它的ReflectedType 返回的則是相當(dāng)于 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());
}

產(chǎn)生的輸出如下:

查看類型 DemoClass的字段信息:
--------------------------------------------------
名稱:city
類型:System.String
屬性:Public

名稱:title
類型:System.String
屬性:Public, InitOnly

名稱:text
類型:System.String
屬性:Public, Static, Literal, HasDefault

值得一提的是fi.FieldType 屬性,它返回一個FieldAttributes位標(biāo)記,這個位標(biāo)記包含了字段的屬性信息。對比我們之前定義的DemoClass類,可以看到,對于 title 字段,它的屬性是public, InitOnly;對于Const類型的text字段,它的屬性為Public,Static,Literal,HasDefault,由此也可以看出, 聲明一個const類型的變量,它默認(rèn)就是靜態(tài)static的,同時,由于我們給了它初始值,所以位標(biāo)記中也包括HasDefault。

針對于FieldType位標(biāo)記,F(xiàn)iledInfo 類提供了一組返回為bool類型的屬性,來說明字段的信息,常用的有:IsPublic, IsStatic, IsInitOnly, IsLiteral, IsPrivate 等。

如果我們想要獲取私有字段信息,依然可以使用重載了的GetFields[]方法,傳入BindingFlags參數(shù),和上面的類似,這里就不重復(fù)了。

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

從前面的章節(jié)可以看到,Name屬性會在編譯后生成Get_Name()和Set_Name()兩個方法,那么,應(yīng)該可以利用反射獲取這兩個方法。 PropertyInfo類的GetGetMethod()和GetSetMethod()可以完成這個工作,它返回一個MethodInfo對象,封裝 了關(guān)于方法的信息,我們會在后面看到。

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 位標(biāo)記標(biāo)明了方法的一些屬性,常見的比如Abstract, Static, Virtual,Public, Private 等。

與前面不同的是,Method可以具有參數(shù) 和 返回值,MethodInfo 類提供了 GetParameters() 方法獲取 參數(shù)對象的數(shù)組,方法的參數(shù)都封裝在了 ParameterInfo 類型中。查看ParameterInfo類型的方法與前面類似,這里就不再闡述了。

6. ConstructorInfo類型、EventInfo 類型

從名稱就可以看出來,這兩個類型封裝了類型 的構(gòu)造函數(shù) 和 事件信息,大家都是聰明人,查看這些類型與之前的方法類似,這里就不再重復(fù)了。

7.小結(jié)

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

轉(zhuǎn)載地址:http://www./CLR-and-Framework/Reflection-Part2.aspx

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多