2009年10月30日 星期五

取得物件的私有欄位、呼叫已經綁定在物件上的事件

要 using System.Reflection、System.ComponentModel、System.Text 三個命名空間
public string ListFields(Type type)
{
  StringBuilder sb = new StringBuilder();
  FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
  sb.Append(@"<table border='1' cellpadding='3' cellspacing='0'><tr><th>Field Name</th>
              <th>Type</th><th>Static</th></tr>");
  foreach (FieldInfo fInfo in fieldInfos)
  {
    sb.AppendFormat("<tr><td>{0:s}</td><td>{1:s}</td><td>{2:s}</td></tr>",
      fInfo.Name, fInfo.FieldType.FullName, fInfo.IsStatic ? "Yes" : "No");
  }
  sb.Append("</table>");
  return sb.ToString();
}
這樣就可以把 type 裡面定義的私有欄位,用 Table 的方式顯示出來
如果私有欄位定義在 base class 中,則傳入 obj.GetType().BaseType
執行範例一: 
System.Web.UI.WebControls.FormView() FormView1 = new System.Web.UI.WebControls.FormView();
ListFields(FormView1.GetType());
Field Name Type Static
EventPageIndexChanged System.Object Yes
EventPageIndexChanging System.Object Yes
EventItemCommand System.Object Yes
EventItemCreated System.Object Yes
EventItemDeleted System.Object Yes
EventItemDeleting System.Object Yes
EventItemInserting System.Object Yes
EventItemInserted System.Object Yes
EventItemUpdating System.Object Yes
EventItemUpdated System.Object Yes
EventModeChanged System.Object Yes
EventModeChanging System.Object Yes
執行範例二: 
System.Web.UI.WebControls.DropDownList DopDownList1 = new System.Web.UI.WebControls.DropDownList();
ListFields(DropDownList1.GetType());
Field Name Type Static

??怎麼沒有東西??
那麼改用 ListFields(dropDownList1.GetType().BaseType) 試看看
Field Name Type Static
EventSelectedIndexChanged System.Object Yes
EventTextChanged System.Object Yes
果然有了!
拿到這些私有欄位的名稱有什麼用?各位發覺到了嗎,這些私有欄位都是以 Event 開頭的,也就是說這些是用來儲存 Delegate 的私有變數
接下來,就可以利用以下的程式,來呼叫「已經綁定在物件上的事件處理函式」
public void InvokeEvent(object obj, Type type, string eventName, EventArgs e)
{  
  PropertyInfo propertyInfo = (type.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic));
  EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(obj, null);
  FieldInfo fieldInfo = type.GetField(eventName, BindingFlags.Static | BindingFlags.NonPublic);
  Delegate[] dels = eventHandlerList[fieldInfo.GetValue(null)].GetInvocationList();
  foreach (Delegate d in dels)
  {  
    d.Method.Invoke(d.Target, new object[] { obj, e });
  }
}
呼叫範例:
InvokeEvent(DropDownList1, DropDownList1.GetType().BaseType, "EventSelectedIndexChanged", e);