曾經看《大話設計模式》的時候說到 反射反射程序員的歡樂,當時我還不太相信 畢竟自己不太會反射。甚至什么時候用反射我也不太知道,只能說查了些資料知道有一些反射這咱東西僅此而已。
這幾天在做一個人才管理系統,其中有一個讓我糾結的就是 操作日志這塊吧,特別是在修改的時候要記錄每個字段改變前后的情況。好吧,當時有兩個決定方案吧。一、再建了一張和原表相同的結構的唄,再用一個外鍵和原表主鍵連下,做下記錄吧。二、就是在讀取數據的時候存儲兩個Model,一個New Model 一個Old Model唄,然后再對比下。
最后,由于種種的原因選擇了第二次方式。好吧,竟然用第二種說出來一個問題,怎么對比兩個Model來,難道一個個字段對比嗎?天哪這不噩夢嘛,如果有20個字段我不是要寫20多個對比 20多個IF了,這我不干 這明顯就不是最良的代碼好,不過我也沒什么好的辦法 只能問問度娘、GOOOGLE唄,在這個互聯網的時代,要善用搜索引擎嘛,于是找了下。
一開始代碼應該是這樣的。有兩個實體變量,存放的是修改前和修改后的信息。比如:
InfoModel oldModel=new InfoModel();InfoModel newModel=new InfoModel();
需要遍歷這兩個實體類的全部屬性的值來進行對比,并將有差別的列出來。
找到一個解決的方案就是使用反射進行對比
//反射遍歷System.Reflection.PRopertyInfo[] mPi = typeof(InfoModel).GetProperties(); for (int i = 0; i < mPi.Length; i++) { System.Reflection.PropertyInfo pi = mPi[i]; oldValue = pi.GetValue(oldModel, null).ToString(); newValue = pi.GetValue(newModel, null).ToString(); if (oldValue !=newValue ) { 有差別的列出來 } }}View Code
在這里,用一個小問題那就是typeOf是用來放是哪個 MODEL的嘛!還有就是這是什么 oldModel,newModel,如果向這么不就寫死了嘛,每比較一個數據模型類不是都要這樣寫一個方法不是很麻煩,這以前那個對比雖然好了些不會用這么多的IF了 可是還是不能復用的嘛,只知道做軟件設計的做到啥 可維護、可復用、可擴展、靈活性好。
好吧,這個明顯不能復用的嘛。改改唄,最好做到的就是所有的類都可以用這個方法,此時腦子里瞬間就想起了 泛型。【泛型類和泛型方法同時具備可重用性、類型安全和效率,這是非泛型類和非泛型方法無法具備的。泛型通常用與集合以及作用于集合的方法一起使用。.NET Framework 2.0 版類庫提供一個新的命名空間System.Collections.Generic,其中包含幾個新的基于泛型的集合類。泛型是 C# 2.0 的最強大的功能。通過泛型可以定義類型安全的數據結構,而無須使用實際的數據類型。這能夠顯著提高性能并得到更高質量的代碼,因為您可以重用數據處理算法,而無須復制類型特定的代碼。在概念上,泛型類似于 C++ 模板,但是在實現和功能方面存在明顯差異。】這是從MSDN對泛型的介紹,好吧,我想這個功能應該可以滿足我的要求,把代碼改改唄
1 public string CompareModel<T>(T newModel, T oldModel) 2 { 3 StringBuilder strLog = new StringBuilder(); 4 System.Reflection.PropertyInfo[] mPi = typeof(T).GetProperties(); 5 for (int i = 0; i < mPi.Length; i++) 6 { 7 System.Reflection.PropertyInfo pi = mPi[i]; 8 string strName = string.Empty; 9 string log = string.Empty;10 if (pi.GetValue(oldModel, null) != null && pi.GetValue(newModel, null) != null)11 {12 string name = pi.Name;//字段名13 string oldValue = pi.GetValue(oldModel, null).ToString();//獲取對應字段的值14 string newValue = pi.GetValue(newModel, null).ToString();15 if (oldValue != newValue)16 {//具體差異的操作17 strLog.AppendFormat("{0}從{1}改為{2}", name, oldValue, newValue);18 }19 }20 }21 return strLog.ToString();22 }View Code
這樣也可以一一的不同的數據列出來了,可這里還有一個問題就是其中的NAME是英文的啊,總不可能給客戶看英文的吧,再想想辦法唄。在這里看到PropertyInfo 有個GetCustomAttributes 的方面,這不就是可以獲取特性的方法嘛,特性我知道就啊,就想在MVC中Model類里的字段上前的 [Display(Name = "用戶名")] 這種東東嘛,好吧,我也有這個樣的吧,雖然Attributes 是可以自定義的,但我還是小小的懶下使用MVC里的算了,自己寫也太麻煩,自己本身對這個也不太會用嘛,只能算是拿來主義。開心的引用了using System.ComponentModel.DataAnnotations;
1 using System; 2 using System.ComponentModel.DataAnnotations; 3 4 public class LoginModel 5 { 6 7 [Display(Name = "用戶名")] 8 public string UserName { get; set; } 9 10 public string ExternalLoginData { get; set; }11 }12 /// <summary>13 /// 說明:對比實體類14 /// 時間:2014年2月20日 14:17:4815 /// Auhter:Kim16 /// </summary>17 /// <typeparam name="T"></typeparam>18 /// <param name="newModel"></param>19 /// <param name="oldModel"></param>20 /// <returns></returns>21 public string CompareModel<T>(T newModel, T oldModel) where T : class,new ()22 {23 StringBuilder strLog = new StringBuilder();24 System.Reflection. PropertyInfo[] mPi = typeof(T).GetProperties();25 for (int i = 0; i < mPi.Length; i++)26 {27 System.Reflection. PropertyInfo pi = mPi[i];28 string strName = string .Empty;29 string log=string .Empty;30 if (pi.GetValue(oldModel, null ) != null && pi.GetValue(newModel, null ) != null)31 {32 33 strName = Attributes.GetDisplayInfo<T>(pi.Name);34 string oldValue = pi.GetValue(oldModel, null).ToString();35 string newValue = pi.GetValue(newModel, null).ToString();36 if (oldValue != newValue)37 {38 if (GetNameByDictonary(strName, oldValue, newValue, out log))39 strLog.Append(log);40 else41 strLog.AppendFormat("<strong>{0}</strong><span>{0} 從 {1} 改為 {2}</span> ", strName, oldValue, newValue);42 }43 }44 }45 return strLog.ToString();46 }47 48 49 /// <summary>50 /// 獲取DisplayInfo51 /// </summary>52 /// <param name="t"></param>53 public static string GetDisplayInfo<T>( string name) where T : class,new ()54 {55 Type objType = typeof (T);56 // Using reflection.57 string strName = string .Empty;58 PropertyInfo propInfo = objType.GetProperty(name);59 object[] attrs = propInfo.GetCustomAttributes(typeof (DisplayAttribute), true); // Reflection.60 // Displaying output.61 if (attrs.Length > 0)62 {63 DisplayAttribute a = attrs[0] as DisplayAttribute;64 strName = a.Name;65 }66 67 return strName;68 }View Code
這樣的代碼也基本的符合要求了,不過小弟在這還有一個不解的地方就是說,有一些數據實體類型的字段是別的表的外鍵嘛,這又要怎么正常在的數據顯示出來哪?希望各位大神 指導一二,各位碼農、碼友們有些好的解決方案 也探討下唄,提出你們的寶貴意見,小弟先在這里謝過了!
新聞熱點
疑難解答