Jen

關鍵報告之Reflection真的很好用

最近在修改一個會員積點兌換贈品的網站,而要成為會員之前一定要填好問卷,而這個問卷在資料庫的設計是這樣的……

1

一個會員的基本資料跟問卷的選項答案開成一個表格,A1、A1Txt、A2、A3…到A12_1、A12_2總共有12題,六十多個選項加上會員的基本資料欄位,這樣的設計是真的很笨(真的很白爛的設計耶)也很沒有彈性,雖然容易理解跟閱讀,笨笨的程式碼變得好多多好多,在當時非常急迫的時程上也沒有想過那麼多。其實在越令人不安害怕的時程裏,就要越仔細去思考任何可能發生的需求變動,在目前這種沒有制式文件、規則不確定及需求變動性很大的環境中,考驗著你架構程式的彈性。當然任何需求都可以改,只是修改的時間成本多寡的問題,會不會影響其他進行中專案的時間或者跟女朋友約會的時間(誤)。有時候我在想,我大可用已經寫好的程式一套招式打到底,何必每接到新案子都在思考新的架構,怎麼寫才會更好,更漂亮,面對PM一些機車的需求修改能沒有沒有任何掛慮的說YES ! I DO!

 

 

每天你都得前進一點點. 你的程式不好有錯還是沒人要, 這全都沒關係. 只要你一直進行, 持續的寫程式並修正錯誤, 時間就會站在你這邊--------約耳談程式

 

程式設計是一門技術,更是一門藝術,不能只滿足於寫完程式碼執行結果正確就了事,要經常思考如何讓程式碼更簡練,更加容易維護,容易擴展和複用----大話設計模式 

 

不要再說程式設計只是複製貼上,如果是請個小妹妹來做吧。自已都看不清自已的價值在哪,更別寄望別人會看得到。

 

 

不過這扯太遠了,今天是想分享一個好用的Reflection類別,先看看我在新增會員問卷答案或修改答案的時候是怎麼寫的,貼出來也不怕人家笑,自已都覺得好笑。

 

在Model層寫了一個UpdateQuestion,把傳到ControllerFormCollection 丟進來更新到Jen_Member的物件屬性去。

 

protected void UpdateQuestion(JEN_Memeber member, FormCollection formvalues)
{
    //第一題
    if (formvalues["Customer.A1"] != null) member.A1 = 
                     formvalues["Customer.A1"].ToString();
    //第二題文字
    if (formvalues["Customer.A1Txt"] != null) member.A1Txt = 
                      formvalues["Customer.A1Txt"].ToString();
    //第二題
    if (formvalues["Customer.A2"] != null) member.A2 = 
                      formvalues["Customer.A2"].ToString();
    //第三題
    if (formvalues["Customer.A3_1"] != null) member.A3_1 = 
                       formvalues["Customer.A3_1"].ToString();
    //....
    //怒刪
    //.... 
    //第十二題
    member.A12_5 = 
     (formvalues["Customer.A12_5"] != null) ? formvalues["Customer.A12_5"].ToString() : "";

    member.A12_5Txt = 
     (formvalues["Customer.A12_5Txt"] != null) ? formvalues["Customer.A12_5Txt"].ToString() : "";

}  

 

 

你可能會問為什麼不用預設的ModelBinder去做,其實這也是當初資料結構沒設計好的緣故。

 

假設我的第一題有3個多選的選項(checkBox),我就會有3個欄位分別是A1_1、A1_2、A1_3,有被勾選的就是存"1",沒有被勾選的就是存"0"。在View當中,我是使用Html.CheckBox,所以有被勾選到的,在ModelBinder接到的值會是字串"True" 或者是"False",所以這樣ModelBinder來Mapping值會有問題(當然可以寫ModelBinder來解決,但這又是另一個議題了。)

 

那我要怎麼把上面那一串垃圾的81行程式利用reflection來濃縮到10行以內呢?d

 

 

 

/// <param name="entity">要更新的物件</param>
/// <param name="formvalues">form value的集合</param>
/// <param name="strPrefix">前置詞</param>
protected void UpdateQuestionByProperty
(JEN_Memeber entity, FormCollection formvalues,string strPrefix)
{
     //並不是每個會員欄位都要更新,我只要更新問卷欄位的部分
     //問卷選項欄位的名命有個規則,可以用Regular來解決
     //A1、A2_1、A2_2、A2_2Txt…
     Regex Rgx = new Regex("A\\d{1,2}(_\\d{1,2}(Txt)?)?");
 
     //先取得所有的PropertyInfo,當然你可以用BindingFlags來做一個Filter
     //可以到google.com找「MSDN2 BindingFlags」來study它的用法.
     PropertyInfo[] aryPinfo = entity.GetType().GetProperties();
 
     //列舉Property 
     foreach (PropertyInfo Property in aryPinfo)
     {
         //如果Property的Name符合問卷欄位名稱的規則,我們就來更新.
         if (Rgx.IsMatch(Property.Name))
         {
             string strKey = 
             string.Format("{0}.{1}", strPrefix, Property.Name);
             //要注意為什麼多這一段,
             //用Html.CheckBox,只要有被勾選的,在Formvalue[key]會傳回
             //"true,false"這樣的字串
             string strValue = 
          (formvalues[strKey] != null) ? formvalues[strKey].Split(new char[] { ',' })[0] : "false";
 
            //更新相對應的值 
            Property.SetValue(entity, (strValue.ToLower() == "true") ? "1" : "0",null);          
         }
     }
}
 
註解不要算應該不到10行字吧,真的很好用,而且可以應用在很多很多地方。
 
http://msdn.microsoft.com/en-us/library/system.reflection.aspx
http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags.aspx
 
  

0 意見: