1. 程式人生 > >C# 反射(Reflection)的用處分析

C# 反射(Reflection)的用處分析

roi 文章 acc contain fin oid bject 打印 normal


亂侃

作為一名新手,一直沒有勇氣去寫一篇分享。原因有很多:諸如:自己水平有限、語言表達不準確、寫出的東西沒有一點技術點被人嘲笑。今天在公司聽了內部員工的一個分享,其中最重要的一點是:提升自身水平的最佳的途徑就是――交流。不管你是通過什麽途徑,交流也好、整理成文字分享也好等等都是很好的方式。故此,今天獻醜寫一篇自己的心得分享,歡迎各路大神的指教!


需求背景

今天接到的需求裏面有個這樣的需求,如下圖所示,需要打印出如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)的用處分析