CODE-Reflection範例

Reflection是在執行期間才解析物件類別資訊的技術,在不少場合,要處理的物件類別在編譯時期是無法預知的,或是希望能保留彈性,以便接受包容各種物件。當傳進來的物件參數類別是object,卻又想一探它的底細,就是System.Reflection命名空間神奇工具組上場的時候。

印象中Reflection與編譯期確定型別相比,效率頗差,每次要動用時總有些畏首畏尾的。但我後來發現MS在BCL內,自己倒用Reflection用得很盡興,加上新一代的CPU愈來愈快,效能差異的顯著性正大幅降低。慢慢地我才開始比較大膽應用它解決問題,執行期才動態識別物件的做法,在某些場合大幅簡化程式的複雜度,有時甚至是形成10行Code對100行Code的差距。

每次要寫Reflection都要重新查文件,索性留文一篇給自己也給大家參考。

以下的例子利用Reflection的技術剖析傳入的未知類別object物件,一一巡弋自訂類別SecrectObject的Field、Property,連宣告private的也不放過,呵呵。最後再示範了如何呼叫Method。

using System;
using System.Reflection;
using System.Diagnostics;
 
public class SecretObject
{
    public string PublicProperty { get; set; }
    private string PrivateProperty { get { return "Secrect"; } }
    public string PublicField = "Public";
    private string PrivateField = "Private";
    public static string StaticField = "Static";
    public void SayHello(string name)
    {
        Console.WriteLine("Hello, " + name);
    }
}
 
public class CSharpLab
{
    public static void Test() 
    {
        SecretObject so = new SecretObject();
        so.PublicProperty = "Open";
        Analyze(so);
    }
 
    public static void Analyze(object obj)
    {
        Type t = obj.GetType();
        Console.WriteLine("Type Name={0}", t.Name);
        foreach (FieldInfo f in t.GetFields(
            BindingFlags.Public | BindingFlags.NonPublic |
            BindingFlags.Instance | BindingFlags.Static))
            Console.WriteLine(
                "Field [{0}] = {1}", f.Name, f.GetValue(obj));
        foreach (PropertyInfo p in t.GetProperties(
            BindingFlags.Public | BindingFlags.NonPublic |
            BindingFlags.Instance | BindingFlags.Static))
            Console.WriteLine("Property [{0}] = {1}",
                                p.Name, p.GetValue(obj, null));
        foreach (MethodInfo m in t.GetMethods(
            BindingFlags.Public | BindingFlags.Instance ))
        {
            if (m.Name == "SayHello")
            {
                Console.WriteLine("Method [SayHello] Found!");
                foreach (ParameterInfo a in m.GetParameters())
                    Console.WriteLine(" - Parameter : " + a.Name);
                m.Invoke(obj, new object[] { "Jeffrey" });
            }
        }
    }
}

[程式碼可使用MiniCSharpLab直接執行]

歡迎推文分享:
Published 01 December 2008 06:12 AM 由 Jeffrey
Filed under: ,
Views: 14,711



意見

# chiyuan said on 20 July, 2009 12:05 AM

大大最近在閱讀Reflection

找到你的文章

我也試著把程式碼貼到 Mini C# Lab Ver 1.3

卻不能work

error message:

Compilation Errors:

Line: 7 Column 36 - 'SecretObject.PublicProperty.get' 不是標記成 abstract 或 extern,因此必須宣告主體

Line: 7 Column 41 - 'SecretObject.PublicProperty.set' 不是標記成 abstract 或 extern,因此必須宣告主體

請問那邊有漏掉?

謝謝

# chiyuan said on 20 July, 2009 12:13 AM

大大

請問上述code是要選 .net 3.5 ?

我選3.5 執行無誤~

3q3q

# Jeffrey said on 20 July, 2009 08:41 AM

to chiyuan, 它有用到C# 3.0+才有的自動實作屬性(blog.darkthread.net/.../c-3-auto-imp-prop.aspx) ,所以要選.NET 3.5囉。

# vance said on 25 August, 2015 05:44 AM

大大您好

最近在研究有關Reflection的議題,

不好意思把您很久以前的文章挖出來(我太晚學寫程式了...)。

有個問題想請教您,在使用assembly.CreateInstance動態建立物件時,

若該物件本身有邏輯錯誤,出現內部Exception時,應該要用甚麼方式避免主程式Crash?

由於動態建立的物件並非自己開發,而對方程式若沒有做好Exception管理,

就會造成我們主程式在建立物件時一同出現Error,

我有試過主程式加上TRY CATCH的處理,但仍然無法避免,

不知您有處理過類似的狀況嗎?

萬分感謝~~

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<December 2008>
SunMonTueWedThuFriSat
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication