[ASP.NET] 利用反射方法(Type.InvokeMember)取得不同資料物件屬性

  • 19743
  • 0
  • 2013-06-09

摘要:[ASP.NET] 利用反射方法(Type.InvokeMember)取得不同資料物件屬性

前言


  反射方法算是 C# 比較進階的使用,Type.InvokeMember 方法可以在執行時期動態繫結物件屬性或方法,以下舉個例子來說明。

 

範例


  我有兩個不同的資料物件和一個輸出方法,兩個資料物件將由使用者在執行時期的操作而產生對應的資料物件,並且使用同一個輸出方法來列印資料物件的值,該怎麼做呢? 下面來實作一下。

  先建立兩個 Value Object:

UserVo


public class UserVo
{
    private string _name;
    public string name
    {
        get { return _name; }
        set { 
            _name = value;
            _PropertyNames.Add("name");
        }
    }

    private List<string> _PropertyNames = new List<string>();
    public List<string> PropertyNames
    {
        get { return _PropertyNames; }
        set { _PropertyNames = value; }
    }

    public object GetPropertyValue(string propName)
    {
        switch (propName)
        {
            case "name":
                return name;
            default:
                return "";
        }
    }
}

 

ProductVo


public class ProductVo
{
    private int _pid;
    public int pid
    {
        get { return _pid; }
        set {
            _pid = value;
            _PropertyNames.Add("pid");
        }
    }

    private string _proName;
    public string proName
    {
        get { return _proName; }
        set { 
            _proName = value;
            PropertyNames.Add("proName");
        }
    }

    private List<string> _PropertyNames = new List<string>();
    public List<string> PropertyNames
    {
        get { return _PropertyNames; }
        set { _PropertyNames = value; }
    }

    public object GetPropertyValue(string propName)
    {
        switch (propName)
        {
            case "pid":
                return pid;
            case "proName":
                return proName;
            default:
                return "";
        }
    }
}

 

  在這兩個資料物件中,除了本身的一些屬性之外,我額外增加了 PropertyNams 屬性跟 GetPropertyValue 方法,PropertyNams 屬性用來存放有給予值的屬性名稱以便於之後呼叫,GetPropertyValue 方法用來取得與屬性名稱對應之值。

 

  在將資料物件處理完成後,就要來實際使用 InvokeMember 方法在執行時期將產生的物件屬性顯示,建立一個 aspx 網頁,並在畫面上拖入兩個按鈕,如下。

 

  切換到後置程式碼畫面,在兩個按鈕事件中分別建立不同的資料物件,並將物件傳至 PrintData 方法:


protected void Button1_Click(object sender, EventArgs e)
{
    UserVo myVo = new UserVo();
    myVo.name = "Arvin";
    PrintData(myVo);
}

protected void Button2_Click(object sender, EventArgs e)
{
    ProductVo myVo = new ProductVo();
    myVo.pid = 101000001;
    myVo.proName = "Product_101";
    PrintData(myVo);
}

 

  在此使用 Type.InvokeMember 方法 (String, BindingFlags, Binder, Object, Object[]),語法如下:


public Object InvokeMember(
	string name,
	BindingFlags invokeAttr,
	Binder binder,
	Object target,
	Object[] args
)
  • name:要呼叫的屬性或方法名稱
  • invokeAttr位元遮罩,如BindingFlags.GetProperty(取屬性)或BindingFlags.InvokeMethod(叫用方法)等
  • binder定義一組屬性並啟用繫結的物件
  • target要呼叫的該物件成員
  • args要傳入呼叫的成員的引數陣列

 

  在 PrintData 方法中,先使用 getType() 取得該物件型別,因為了讓 PrintData 方法於不同的資料物件都能使用,傳入的資料物件是使用 object 去接收,取得了 objType 之後,使用反射的方式將資料物件的 PropertyNames 屬性取得,invokeAttr 參數使用的是 BindingFlags.GetProperty (取得公開屬性),而取得了 PropertyNames 後就可以使用迴圈將資料讀出,而在讀取資料時將 invokeAttr 參數改成 BindingFlags.InvokeMethod (調用方法) 則變成呼叫方法。


private void PrintData(object objVo)
{
    Type objType = objVo.GetType();
    // 取得屬性名稱集合
    List<string> names = (List<string>)objType.InvokeMember(
            "PropertyNames",
            System.Reflection.BindingFlags.GetProperty,
            null, objVo, new object[] { });
    // 將所有屬性值印出
    foreach (string name in names)
    {
            Response.Write(objType.InvokeMember(
            "GetPropertyValue",
            System.Reflection.BindingFlags.InvokeMethod,
            null, objVo, new object[] { name }) + "</br>");
    }
}

 

  完成後,實際執行結果如下:

 

 

  另外補充,在 .NET Framework 4.0 C# 中多了 dynamic 型別,如果在此將 PrintData 的傳入參數改成 dynamic 型別後,呼叫成員的方法就可以不使用反射的方式,可以直接叫用該方法即可。

 

範例下載


TInvokeMember.rar

 

參考資料


Type.InvokeMember 方法 (String, BindingFlags, Binder, Object, Object[])

dynamic (C# 參考)

 

 


以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教
如有侵權內容也請您與我反應~謝謝您 :)