Reflection demo

反映 Refection

.NET提供的類別來實作反映

.NET提供了非常非常多讀取中繼資料的類別,大多數都在System.Reflection命名空間底下,這些類別可以動態載入程式集、呼叫模組、型別、方法、欄位等。
上一篇所說的,程式集包含很多模組,模組包含很多型別,型別包含很多欄位和方法,所以為了讓讀者能了解,將包含的內容實體化,我們從最常用的型別開始往下分析。

先建立要被分析的特性(Attribute)與類別

//[AttributeUsage(AttributeTargets.Class)] 說明此Attribute是使用在class上面
[AttributeUsage(AttributeTargets.Class)]
public class ShowAttribute : Attribute
{
    private string Message { get; set; }
    public ShowAttribute(string message)
    {
        this.Message = message;
    }

    public void PrintMessage() 
    {
        Console.WriteLine(Message);
    }
}
[ShowAttribute("hi")]
public class AnalyzedClass
{
    public string _stringField;

    public int _intField;

    public string MyProperty1 { get; set; }

    public string MyProperty2 { get; set; }

    public void Method() 
    {
        Console.WriteLine("I'm Method");
    }

    public string ReturnValueMethod(string message) 
    {
        return message;
    }
}

開始分析逐一分析

分析流程:

型別→成員→方法→方法參數→屬性→特性

static void Main(string[] args)
{
    AnalyzedClass ac = new AnalyzedClass();

    Type type = ac.GetType();
    
    // 分析Type
    AnalyzeType(type);

    // 分析成員
    AnalyzeFieldInfo(type.GetFields());

    //分析方法
    AnalyzeMethodInfo(type.GetMethods());

    //分析方法參數
    foreach (var method in type.GetMethods())
    {
        AnalyzeMethodParameterInfo(method.GetParameters());
    }
    //分析屬性
    AnalyzeProperyInfo(type.GetProperties());

    //分析特性
    AnalyzeAttributeInfo(type);

}

// 分析Type
private static void AnalyzeType(Type type)
{
    // 型別名稱
    Console.WriteLine("型別名稱: " + type.Name);
    // output: AnalyzedClass

    // 型別種類
    Console.WriteLine("型別種類: " + type.Attributes);
    // output: AutoLayout, AnsiClass, Class, public, BeforeFieldInit

    // 型別的GUID
    Console.WriteLine("型別的GUID: " + type.GUID);
    // output:be2ebf30-5119..........
}

//分析成員
private static void AnalyzeFieldInfo(FieldInfo[] fields) 
{
    foreach (var field in fields)
    {
        // 成員名稱
        Console.WriteLine("成員名稱: " + field.Name);
        // output: _stringField 與 _intField

        // 成員種類
        Console.WriteLine("成員種類: " + field.Attributes);
        // output: public 與 public
        
        // 成員型別
        Console.WriteLine("成員型別: " + field.FieldType);
        // output: System.String 與 System.Int32
    }
}

//分析方法
private static void AnalyzeMethodInfo(MethodInfo[] methods)
{
    foreach (var method in methods)
    {
        // 方法名稱
        Console.WriteLine("方法名稱: " + method.Name);
        // output: Method 與 ReturnValueMethod

        // 方法類別
        Console.WriteLine("方法類別: " + method.Attributes);
        // output: PrivateScope, Public, HideBySig 
        //         與 PrivateScope, Public, HideBySig 

        // 實際上output : 還有很多沒列出來,例如get,set 的 property方法
        // 與物件的方法,例如GetType,ToString,Equals....等。
        // 這些方法都會被分析出來
    }
}

//分析方法參數
private static void AnalyzeMethodParameterInfo(ParameterInfo[] parameters)
{
    foreach (var parameter in parameters)
    {
        // 參數名稱
        Console.WriteLine("參數名稱: " + parameter.Name);
        // output: message

        // 參數種類
        Console.WriteLine("參數種類: " + parameter.Attributes);
        // output: None

        // 參數型別
        Console.WriteLine("參數型別: " + parameter.ParameterType);
        // output: System.String
    }
}

//分析屬性
private static void AnalyzeProperyInfo(PropertyInfo[] properites)
{
    foreach (var properiy in properites)
    {
        // 屬性名稱
        Console.WriteLine("屬性名稱: " + properiy.Name);
        // output : MyProperty1 與 MyProperty2

        // 屬性型別
        Console.WriteLine("屬性型別: " + properiy.PropertyType);
        // output : System.String 與 System.String

        // 屬性種類
        Console.WriteLine("屬性種類: " + properiy.Attributes);
        // output : None 與 None

        //是否可讀
        Console.WriteLine("是否可讀: " + properiy.CanRead);
        // output : true 與 true

        //是否可寫
        Console.WriteLine("是否可寫: " + properiy.CanWrite);
        // output : true 與 true

    }
}

//分析特性
private static void AnalyzeAttributeInfo(Type type)
{
    // 取得屬性類別
    ShowAttribute attr = Attribute.GetCustomAttribute(type, typeof(ShowAttribute)) as ShowAttribute;

    attr.PrintMessage(); // output : hi
    
}

.NET提供的Reflection類別實在太多了,所以大概懂Type有什麼常用的類別就差不多了,到時需要再查MSDN。

上面程式碼分析了那麼多類別,接下就可以取用該類別,做一些事情,例如取用PropertyInfo 給Property值的方法:

AnalyzedClass ac = new AnalyzedClass();

// 先取得Type
Type type = ac.GetType();

// 取得Properies
PropertyInfo[] properties = type.GetProperties();

// 遍歷到我要設定的property
foreach (PropertyInfo property in properties)
{
    // Set Value
    switch (property.Name)
    {
        case "MyProperty1":
            property.SetValue(ac, "Set Hello");
            break;
        case "MyProperty2":
            property.SetValue(ac, "I'm Fine");  
            break;
    }
}

// 此時ac就可以取用
Console.WriteLine("1 : " + ac.MyProperty1); // output : 1 : Set Hello
Console.WriteLine("2 : " + ac.MyProperty2); // output : 2 : I'm Fine

// 或者也可以用Reflection的方式取值
// 取得內容同上
foreach (PropertyInfo property in properties)
{
    Console.WriteLine("Value : " + property.GetValue(ac));
}
.NET提供了這麼多實現反映機制的類別,程式師能夠很方便讀取中繼資料,動態建立物件的功能,了解Reflection的基本原理,寫底層的程式碼時,能夠提供很大的幫助。

 

 

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

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