C# 反射(Reflection)的用處分析
亂侃
作為一名新手,一直沒有勇氣去寫一篇分享。原因有很多:諸如:自己水平有限、語言表達不準確、寫出的東西沒有一點技術點被人嘲笑。今天在公司聽了內部員工的一個分享,其中最重要的一點是:提升自身水平的最佳的途徑就是――交流。不管你是通過什麽途徑,交流也好、整理成文字分享也好等等都是很好的方式。故此,今天獻醜寫一篇自己的心得分享,歡迎各路大神的指教!
需求背景
今天接到的需求裏面有個這樣的需求,如下圖所示,需要打印出如Excel內容呈現的單據。
動手操作第一版本
而為了實現這個業務需要涉及三張表的數據。(存放單據的表、審核意見表、審核狀態表)
三張表的關系:單據表1:1審核狀態表,單據表1:N審核意見表
為了實現讓View頁面整潔,我定義了一個SpecialPrintModel類
public class SpecialPrintModel { /// <summary> /// 供應商承擔 /// </summary> public string SupplierUnderTaker { get; set; } /// <summary> /// 客戶訂單號 /// </summary> public string CustomerSerialNumber { get; set; } /// <summary> /// 付款金額 /// </summary> public decimal PayAmount { get; set; } /// <summary> /// 開戶行 /// </summary> public string OpeningBank { get; set; } /// <summary> /// 收款單位 /// </summary> public string CollectionMonad { get; set; } /// <summary> /// 銀行帳號 /// </summary> public string BankAccount { get; set; } /// <summary> /// 經辦人 /// </summary> public string ResponseiblePerson { get; set; } /// <summary> /// 分管領導 /// </summary> public string Leader { get; set; } /// <summary> /// 財務審核 /// </summary> public string FinanceApproval { get; set; } /// <summary> /// 財務經理審核 /// </summary> public string FinanceManagerApproval { get; set; } /// <summary> /// 財務總監審核 /// </summary> public string FinanceDirectorApproval { get; set; } /// <summary> /// CEO審核 /// </summary> public string CEOApproval { get; set; } /// <summary> /// 流水號 /// </summary> public string SerialNumber { get; set; } }
public List<ShipSpecialPrintModel> GetTobePaidRecepit(ShipSpecialSearch search) { List<ShipSpecialPrintModel> curiseShipModel = new List<ShipSpecialPrintModel>(); var toBePaidModel = persistant.GetTobePaidRecepit(search);//查找出待支付的單據表信息 ArrayList serialArray=new ArrayList();//定義一個流水號列表 toBePaidModel.ForEach((u) => { serialArr.Add(u.SerialNumber); }); var toBePaidComment = persistant.GetTobePaidRecepitComment(serialArr);//查找出待支付單據的審核意見表(1個單據對應多少審核意見) foreach (var item in toBePaidModel) { ShipSpecialPrintModel temp = new ShipSpecialPrintModel() { SupplierUnderTaker = supplierUnderTaker; CustomerSerialNumber = item.CustomerOrderNumber; PayAmount = item.PayAmount; OpeningBank = item.PayBank; CollectionMonad = item.Payee; ResponseiblePerson = item.Creator; SerialNumber = item.SerialNumber; }; curiseShipModel.Add(temp); } foreach (var curise in curiseShipModel) { foreach (var comment in toBePaidComment) { if (comment.SerialNumber == curise.SerialNumber) { if (comment.ApprovalLevel == (int)LevelType.BranchedLeader) { curise.Leader = comment.Creator; } else if (comment.ApprovalLevel == (int)LevelType.Finance) { curise.FinanceApproval = comment.Creator; } else if (comment.ApprovalLevel == (int)LevelType.FinanceManager) { curise.FinanceManagerApproval = comment.Creator; } else if (comment.ApprovalLevel == (int)LevelType.ProjectDirector) { curise.FinanceDirectorApproval = comment.Creator; } else if (comment.ApprovalLevel == (int)LevelType.CEO) { curise.CEOApproval = comment.Creator; } } } } return curiseShipModel }
呵呵,上面的代碼基本完成了業務的需求,可是如果業務需要打印出CTO的名稱、CIO的名稱那在if else這邊加,雖然很簡單但是違背了開放-封閉的原則。故本人決定用反射去完成這if…else的事情。
因為if…else裏面的判斷是當前的這筆單據的審核意見表的層級是不是跟SpecialPrintModel的字段所對應的層級相等,若相等則在對應字段寫入相對應的名稱。決定把SpecialPrintModel這個類修改下。
動手操作第二版本
public class ShipSpecialPrintModel { /// <summary> /// 供應商承擔 /// </summary> public string SupplierUnderTaker { get; set; } /// <summary> /// 客戶訂單號 /// </summary> public string CustomerSerialNumber { get; set; } /// <summary> /// 付款金額 /// </summary> public decimal PayAmount { get; set; } /// <summary> /// 開戶行 /// </summary> public string OpeningBank { get; set; } /// <summary> /// 收款單位 /// </summary> public string CollectionMonad { get; set; } /// <summary> /// 銀行帳號 /// </summary> public string BankAccount { get; set; } /// <summary> /// 經辦人 /// </summary> public string ResponseiblePerson { get; set; } /// <summary> /// 分管領導 /// </summary> [LevelAttribute(Level = 1)] public string Leader { get; set; } /// <summary> /// 財務審核 /// </summary> [LevelAttribute(Level = 2)] public string FinanceApproval { get; set; } /// <summary> /// 財務經理審核 /// </summary> [LevelAttribute(Level = 3)] public string FinanceManagerApproval { get; set; } /// <summary> /// 財務總監審核 /// </summary> [LevelAttribute(Level = 4)] public string FinanceDirectorApproval { get; set; } /// <summary> /// CEO審核 /// </summary> [LevelAttribute(Level = 5)] public string CEOApproval { get; set; } /// <summary> /// 流水號 /// </summary> public string SerialNumber { get; set; } } public class LevelAttribute : Attribute { public int Level { get; set; } }
var toBePaidComment = persistant.GetTobePaidRecepitComment(ArrayList.Adapter(toBePaidModel.Select(u => u.SerialNumber).ToList())); var specialPropertyInfo = (from property in typeof(CuriseShipSpecialPrintModel).GetProperties() where property.GetCustomAttributes(typeof(LevelAttribute), false).Count() > 0 select property).ToList(); toBePaidModel.ForEach((item)=>{ ShipSpecialPrintModel temp = new ShipSpecialPrintModel() { SupplierUnderTaker = supplierUnderTaker; CustomerSerialNumber = item.CustomerOrderNumber; PayAmount = item.PayAmount; OpeningBank = item.PayBank; CollectionMonad = item.Payee; ResponseiblePerson = item.Creator; SerialNumber = item.SerialNumber; }; var thisComments=toBePaidComment.Where(u=>u.SerialNumber =item.SerialNumber ).ToList(); thisComment.ForEach((cm)=> { if(cm.ApprovalLevel==(specialPropertyInfo.GetCustomAttributes(typeof(LevelAttribute),false).First() as LevelAttribute).Level) { cm.SetValue(model,cm.Creator,null); } }); })
然而看到,propertyInfos那邊基本上每循環一次都需要去反射查找下元素,為了避免這樣的性能消耗,決定再修改一翻,定義一個字典去存儲SpecialPrintModel標有特性類的字段。
動手操作第三版本
Dictionary<int, PropertyInfo> dic = new Dictionary<int, PropertyInfo>(); propertyInfos.ForEach((myProperty) => { dic.Add((a.GetCustomAttributes(typeof(LevelAttribute),false).First() as LevelAttribute).Level,myProperty)); } ); comments.ForEach((cm) => { if (dic.Keys.Contains(cm.ApprovalLevel)) { dic[cm.ApprovalLevel].SetValue(model, cm.Creator, null); } });
總體經過三次的修改,已經避免if…else的代碼。這樣而言,也比較適合後面比如再需要打印CTO審核的名稱。那樣只需要再Model類裏面填寫字段與在字段上加上個特效。
總結
就像我同事說的那樣,做任務事情只要想想、多敲幾次。一些問題就不是問題了。好了,今天就寫到這裏吧。晚安各位!
請您花一點時間將文章分享給您的朋友或者留下評論。我們將會由衷感謝您的支持!
C# 反射(Reflection)的用處分析
本文地址: http://www.paobuke.com/develop/c-develop/pbk23084.html
相關內容
C#計算器編寫代碼TortoiseSVN使用教程C#模擬window操作鼠標的方法C#實現xml文件反序列化讀入數據到object的方法C#中多態現象和多態的實現方法C#自定義RSA加密解密及RSA簽名和驗證類實例C#為配置文件加密的實現方法C#采用Winform實現類似Android的Listener
C# 反射(Reflection)的用處分析