How to get Type data

Type類別

在取得型別之前,得先說明什麼是中繼資料(Metadata)、什麼是反映(Reflection)

中繼資料(Metadata)

描述資料的資料,就是中繼資料!? (蛤?
在CLR中,中繼資料就是描述一個模組的定義或其參考的所有東西。因為CLR程式設計是物件導向的,所以中繼資料描述的東西就是類別和它們的成員,及其伴隨而來的特性、屬性和關聯。中繼資料正是反映(Reflection)機制能夠運作的基礎,中繼資料儲存了類別內部所有資訊,表示程式可以動態地得到整個程式集內部結構。
中繼資料包含:
  • 型別名稱
  • Assembly區塊
  • 建構式
  • 屬性
  • 方法
  • 特性

聽起來很抽象,就讓我們把中繼資料具現化吧!!!

我先建立一個有屬性、建構式跟方法的簡單類別

// 類別名稱
class Program
{
    // 屬性
    public int Score { get; set; }

    // 建構式
    public Program(int score)
    {
        this.Score = score;
    }

    // 方法
    public string GetHelloString() 
    {
        return "Hello";
    }

    static void Main(string[] args)
    {
        Console.WriteLine("Hey");
        Console.Read();
    }
}

Release編譯後,利用反組譯工具ILDasm.exe工具檢查中繼資料

可以很清楚看到Program類別底下

  • 有一個傳入int32的.ctor建構式
  • 回傳string() GetHelloString方法
  • 無回傳值Main方法
  • 屬性 get_Score,set_Score
程式集的所有內部資訊都在中繼資料一覽無遺,並且中繼資料的資料結構是標準固定的,這使得外部程式碼可以動態地獲取程式集的資訊並加以使用,這也完成了.NET最獨特的一個特性:反映

反映(Reflection)

反映提供一種動態分析、建立和呼叫的機制。在.NET框架中,一個系統可以由多個程式集組成,一個程式集可能包含很多模組,而一個模組中會有很多型別,每個型別可以包含欄位的和方法,方法又可以包含輸入參數和輸出參數等多種資料,在.NET中反映機制可以動態地分析程式集,並且使用程式集中的類別和方法。

 

取得型別(Type)

在使用反映之前,要先知道如何取得型別,以下將介紹幾個取得型別的方式,懂得取得型別後,就可以開始使用反映分析、存取資料。
public class Animal
{
    public Animal()
    {
        this.NumberOfLegs = 4;
    }

    public Animal(int number)
    {
        this.NumberOfLegs = number;
    }

    public int NumberOfLegs { get; set; }

    public string SayWoo() 
    {
        return "Woo";
    }
}

static void Main(string[] args)
{
    var dog = new Animal() { NumberOfLegs = 4 };

    // 方法一 編譯時期取得
    Type t1 = typeof(Animal);            

    // 方法二 執行時期取得
    Type t2 = dog.GetType();

    Console.WriteLine(t2.Name);
    // output: Animal

    Console.WriteLine(t2.FullName);
    // output: HowToGetTypedata.Animal

    Console.WriteLine(t2.Assembly);
    // output: HowToGetTypedata, Version = 1.0.0.0,
    //         Culture=neutral, PublicKeyToken=null

}
方法一與方法二結果是一樣的,最大的差別GetType是從類別實例(instance)取得Type,如果你沒有實例(instance),但是知道類別名稱則是使用typeof。

 

如何動態建立一個型別? 因為上述方法二,是沒有實例的,所以可用動態建立的方式,建立一個實例出來。
方法有兩個
  • Activator.CreateInstance
  • 使用Type.GetConstructors
// 方法一
var newAnimal = Activator.CreateInstance(typeof(Animal)) as Animal;
    
// 方法二
// 使用預設建構式
var animalConstructor = typeof(Animal).GetConstructors()[0];
var newAnimal2 = animalConstructor.Invoke(null) as Animal;
存取屬性
var animal = new Animal();

Type type = animal.GetType();

PropertyInfo property = type.GetProperty("NumberOfLegs");

var value = property.GetValue(animal);

Console.WriteLine(value); // output : 4            
呼叫方法
var animal = new Animal();

Type type = animal.GetType();

MethodInfo method = type.GetMethod("SayWoo");

var value = method.Invoke(animal, null).ToString();

Console.WriteLine(value); // output : Woo    
以上就是Type一些基本運用,下一章節將會詳細介紹反映(Reflection)的應用。

 

 

一天一分享,身體好健康。

該追究的不是過去的原因,而是現在的目的。