C# 反射(Reflection)的用處分析
亂侃
作為一名新手,一直沒有勇氣去寫一篇分享。原因有很多:諸如:自己水平有限、語言表達(dá)不準(zhǔn)確、寫出的東西沒有一點技術(shù)點被人嘲笑。今天在公司聽了內(nèi)部員工的一個分享,其中最重要的一點是:提升自身水平的最佳的途徑就是——交流。不管你是通過什么途徑,交流也好、整理成文字分享也好等等都是很好的方式。故此,今天獻(xiàn)丑寫一篇自己的心得分享,歡迎各路大神的指教!
需求背景
今天接到的需求里面有個這樣的需求,如下圖所示,需要打印出如Excel內(nèi)容呈現(xiàn)的單據(jù)。
動手操作第一版本
而為了實現(xiàn)這個業(yè)務(wù)需要涉及三張表的數(shù)據(jù)。(存放單據(jù)的表、審核意見表、審核狀態(tài)表)
三張表的關(guān)系:單據(jù)表1:1審核狀態(tài)表,單據(jù)表1:N審核意見表
為了實現(xiàn)讓View頁面整潔,我定義了一個SpecialPrintModel類
public class SpecialPrintModel
{
/// <summary>
/// 供應(yīng)商承擔(dān)
/// </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>
/// 經(jīng)辦人
/// </summary>
public string ResponseiblePerson { get; set; }
/// <summary>
/// 分管領(lǐng)導(dǎo)
/// </summary>
public string Leader { get; set; }
/// <summary>
/// 財務(wù)審核
/// </summary>
public string FinanceApproval { get; set; }
/// <summary>
/// 財務(wù)經(jīng)理審核
/// </summary>
public string FinanceManagerApproval { get; set; }
/// <summary>
/// 財務(wù)總監(jiān)審核
/// </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);//查找出待支付的單據(jù)表信息
ArrayList serialArray=new ArrayList();//定義一個流水號列表
toBePaidModel.ForEach((u) => { serialArr.Add(u.SerialNumber); });
var toBePaidComment = persistant.GetTobePaidRecepitComment(serialArr);//查找出待支付單據(jù)的審核意見表(1個單據(jù)對應(yīng)多少審核意見)
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
}
呵呵,上面的代碼基本完成了業(yè)務(wù)的需求,可是如果業(yè)務(wù)需要打印出CTO的名稱、CIO的名稱那在if else這邊加,雖然很簡單但是違背了開放-封閉的原則。故本人決定用反射去完成這if...else的事情。
因為if...else里面的判斷是當(dāng)前的這筆單據(jù)的審核意見表的層級是不是跟SpecialPrintModel的字段所對應(yīng)的層級相等,若相等則在對應(yīng)字段寫入相對應(yīng)的名稱。決定把SpecialPrintModel這個類修改下。
動手操作第二版本
public class ShipSpecialPrintModel
{
/// <summary>
/// 供應(yīng)商承擔(dān)
/// </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>
/// 經(jīng)辦人
/// </summary>
public string ResponseiblePerson { get; set; }
/// <summary>
/// 分管領(lǐng)導(dǎo)
/// </summary>
[LevelAttribute(Level = 1)]
public string Leader { get; set; }
/// <summary>
/// 財務(wù)審核
/// </summary>
[LevelAttribute(Level = 2)]
public string FinanceApproval { get; set; }
/// <summary>
/// 財務(wù)經(jīng)理審核
/// </summary>
[LevelAttribute(Level = 3)]
public string FinanceManagerApproval { get; set; }
/// <summary>
/// 財務(wù)總監(jiān)審核
/// </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那邊基本上每循環(huán)一次都需要去反射查找下元素,為了避免這樣的性能消耗,決定再修改一翻,定義一個字典去存儲SpecialPrintModel標(biāo)有特性類的字段。
動手操作第三版本
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);
}
});
總體經(jīng)過三次的修改,已經(jīng)避免if...else的代碼。這樣而言,也比較適合后面比如再需要打印CTO審核的名稱。那樣只需要再Model類里面填寫字段與在字段上加上個特效。
總結(jié)
就像我同事說的那樣,做任務(wù)事情只要想想、多敲幾次。一些問題就不是問題了。好了,今天就寫到這里吧。晚安各位!
請您花一點時間將文章分享給您的朋友或者留下評論。我們將會由衷感謝您的支持!
相關(guān)文章
C# Xamarin利用ZXing.Net.Mobile進(jìn)行掃碼的方法
這篇文章主要介紹了C# Xamarin利用ZXing.Net.Mobile進(jìn)行掃碼的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
c#異步操作async?await狀態(tài)機(jī)的總結(jié)(推薦)
這篇文章主要介紹了c#異步操作async?await狀態(tài)機(jī)的總結(jié),關(guān)于async和await每個人都有自己的理解,甚至關(guān)于異步和同步亦或者關(guān)于異步和多線程每個人也都有自己的理解,本文通過實例代碼詳細(xì)講解,需要的朋友可以參考下2023-02-02
Unity3D 計時器的實現(xiàn)代碼(三種寫法總結(jié))
這篇文章主要介紹了Unity3D 計時器的實現(xiàn)代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
C#提取PDF表單數(shù)據(jù)的實現(xiàn)流程
PDF表單是一種常見的數(shù)據(jù)收集工具,廣泛應(yīng)用于調(diào)查問卷、業(yè)務(wù)合同等場景,憑借出色的跨平臺兼容性和標(biāo)準(zhǔn)化特點,PDF表單在各行各業(yè)中得到了廣泛應(yīng)用,本文將探討如何使用C# 實現(xiàn)自動化PDF表單數(shù)據(jù)提取流程,需要的朋友可以參考下2025-01-01

