有時候,我們會以下拉式選單呈現的方式讓User選擇想要的功能,再執行該功能。例如以下拉式選單增加兩個項目,匯出DOC及匯出PDF,並建立兩Class:CExportDOCCExportPDF。分別在Class中建構匯出文件的程式碼,然後在aspx檔的Code Behind中寫個switch條件式,去產生新的執行個體執行方法。Ex:

    CExportDOC doc = new CExportDOC();
    doc.ExecExport();

如此作法,當以後還要再加個新功能時,除了下拉式選單要修改,再增加一個item,Code Behind的switch也要多一條條件式,另外再增加一個Class撰寫功能。要改三個地方實在麻煩。
透過.NET的Reflection反射機制,我們可以動態的產生下拉式選單,而Code Behind也不用再以switch寫,我們要作的,只是專注在功能上的開發。以下為實作的範例 :

Step 1:建立一抽象類別AbsExport.cs,並建立一抽象方法ExecExport();
public abstract class AbsExport
{
        public abstract string ExecExport();
}

Step 2:分別建立CExportDOC、CExportPDF類別,繼承AbsExport抽象類別,並實作ExecExport方法。
 class CExportDOC:AbsExport
{
    public override string
 ExecExport() 
    {
        return "ExecExportDOC"
;
    }
}

public class CExportPDF:AbsExport
{
    public override string
 ExecExport()
    {
        return "ExecExportPDF"
;
    }
}

Step 3:建立CExportContext類別,建立一GetItems方法,用意是藉由迴圈輪巡App_Code,判斷哪個類別是繼承於抽象類別,再以Dictionary型別傳出。
public static class CExportContext
{
    public static Dictionary<stringstring
> GetItems()
    {
        Dictionary<stringstring> dict = new Dictionary<stringstring
>();
        Type[] types = Assembly.Load("App_Code"
).GetTypes();
        foreach (Type type in types)
        {
            if (type.IsSubclassOf(typeof(AbsExport
)))
            {
                dict[type.Name] = type.Name;
            }
        }
        return
 dict;
    }
}
#補充 Window Form寫法:
public static Dictionary<stringstring> GetItems()
{
       Dictionary<stringstring> dict = new Dictionary<stringstring>();
       foreach (Type t in Assembly.Load("專案名稱").GetTypes())
       {
            if (t.IsSubclassOf(typeof(AbsExport)))
            {
                 ClassDescriptionAttribute cls = t.GetCustomAttributes(true)[0] as ClassDescriptionAttribute;
                 dict[cls.ClassDescription] = t.Name;
             }
       }
       return dict;
}

 

Step 4:建立網頁WfrmReflection.aspx,拉入一DropDownList控制項,命名為ddlExport。在Page_Load中取得字典檔,並綁定給ddlExport:
if (!IsPostBack)
{
    ddlExport.DataSource = CExportContext
.GetItems() ;
    ddlExport.DataTextField = "Key"
;
    ddlExport.DataValueField = "Value"
;
    ddlExport.DataBind();
}

Step 5:在WfrmReflection.aspx中再拉入一Button,在Click事件裡以動態產生執行個體的方式執行ExecExport方法。
AbsExport
 ex = Assembly.Load("App_Code").CreateInstance(ddlExport.SelectedValue) as AbsExport;
string
 tmp = ex.ExecExport();
ClientScript.RegisterStartupScript(this.GetType(), """<script>alert('" + tmp + "')</script>");

CreateInstanc中接受字串型態的參數,所以當點了Button後,傳入ddlExport選中的類別名稱字串到CreateInstanc中,就能動態產生執行個體,以此方式取代了siwtch條件式,即使以後再有需要增加ExportXML的功能,也無須修改Code Behind了。

擷取.PNG  擷取2.PNG  

這裡有個缺陷,在下拉式選單中顯示的是類別名稱,不是很直觀,對於User來說,哪懂得這串英文是啥東東,所以,我們希望下拉式選單中是以「類別描述」來具體描述類別名稱,例如ExportDOC以「匯出Word文件」來表示;ExportPDF以「匯出PDF文件」來表示。
這時,我們能夠使用自訂屬性類別的方式,來幫類別訂定一個屬性(ClassDescriptionAttribute),並賦於其值。詳細介紹請參考MSDN
以下為實作ClassDescriptionAttribute類別的部分:
[AttributeUsage(AttributeTargets.Class)]
public class ClassDescriptionAttribute : 
Attribute
{
    public string classDesc { getset
; }
    public ClassDescriptionAttribute(string
 _classDesc)
    {
        classDesc = _classDesc;
    }
}

然後宣告CExportDOC、CExportPDF類別的類別描述,如下圖:

擷取3.PNG  
而剛剛在CExportContext類別裡的GetItems方法也要小改一下,將
dict[type.Name] = type.Name;
改為
ClassDescriptionAttribute key =type.GetCustomAttributes(true)[0] as ClassDescriptionAttribute;
dict[key.classDesc] = type.Name;

GetCustomAttributes方法能取得剛剛我們自訂的classDesc屬性,再透過key.classDesc取得屬性值,也就是我們指定的類別描述文字。
所以我們再次運行WfrmReflection.aspx,可得到下拉式選單中的類別描述,而選取值為類別名稱的效果了。

擷取4.PNG  

後記:
其實ClassDescriptionAttribute這個屬性,微軟已幫我們作好了,只需要using System.ComponentModel,在類別上方加入[Description("類別描述")] ,而ClassDescriptionAttribute key =type.GetCustomAttributes(true)[0] as ClassDescriptionAttribute;改為 DescriptionAttribute key = type.GetCustomAttributes(true)[0] as DescriptionAttribute;一樣可以得到相同的效果。

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 忙裡偷閒 的頭像
    忙裡偷閒

    忙裡偷閒的部落格

    忙裡偷閒 發表在 痞客邦 留言(0) 人氣()