Useful analysis of C reflection (Reflection)

  • 2021-01-02 21:58:25
  • OfStack

The disorderly kan

As a novice, I didn't have the courage to write a share. There are many reasons for this, such as my limited skills, inaccurate language expression, and the fact that I have no technical skills to laugh at. Today, I have heard a share from internal employees in the company, among which the most important one is: the best way to improve my own level is communication. No matter how you do it, it's a great way to communicate, organize, share, etc. Therefore, today to write an ugly one of their own experience to share, welcome each big god's advice!

Demand background

Among the requirements received today, there is such a requirement, as shown in the figure below, which needs to print out the documents presented by Excel.

Get your hands on version 1

And in order to achieve this business needs to involve three tables of data. (Table for storing documents, review comments, review status)
The relationship between the three tables: document table 1:1 audit status table, document Table 1: N audit suggestion table
To make View pages clean, I have defined an SpecialPrintModel class


public class SpecialPrintModel
  {
    /// <summary>
    ///  Supplier commitment 
    /// </summary>
    public string SupplierUnderTaker { get; set; }

    /// <summary>
    ///  Customer order Number 
    /// </summary>
    public string CustomerSerialNumber { get; set; }
    
    /// <summary>
    ///  The payment amount 
    /// </summary>
    public decimal PayAmount { get; set; }

    /// <summary>
    ///  Where it is 
    /// </summary>
    public string OpeningBank { get; set; }

    /// <summary>
    ///  Receiving unit 
    /// </summary>
    public string CollectionMonad { get; set; }

    /// <summary>
    ///  A bank account 
    /// </summary>
    public string BankAccount { get; set; }

    /// <summary>
    ///  agent 
    /// </summary>
    public string ResponseiblePerson { get; set; }

    /// <summary>
    ///  In charge of the leadership 
    /// </summary>
    public string Leader { get; set; }

    /// <summary>
    ///  Financial audit 
    /// </summary>
    public string FinanceApproval { get; set; }

    /// <summary>
    ///  Financial Manager audit 
    /// </summary>
    public string FinanceManagerApproval { get; set; }

    /// <summary>
    ///  Audit by Financial Controller 
    /// </summary>
    public string FinanceDirectorApproval { get; set; }

    /// <summary>
    /// CEO audit 
    /// </summary>
    public string CEOApproval { get; set; }

    /// <summary>
    ///  Serial number 
    /// </summary>
    public string SerialNumber { get; set; }
  }

public List<ShipSpecialPrintModel> GetTobePaidRecepit(ShipSpecialSearch search)
 {
   List<ShipSpecialPrintModel> curiseShipModel = new List<ShipSpecialPrintModel>();
   var toBePaidModel = persistant.GetTobePaidRecepit(search);// Find out the list of documents to be paid 
   ArrayList serialArray=new ArrayList();// define 1 A list of serial numbers 
   toBePaidModel.ForEach((u) => { serialArr.Add(u.SerialNumber); });
   var toBePaidComment = persistant.GetTobePaidRecepitComment(serialArr);// A review response form to locate documents to be paid (1 How many audit opinions are corresponding to each document )
   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
 }

Well, the above code basically completes the business requirements, but if the business needs to print the name of CTO and CIO then add it to if else, which is simple but violates the open-close principle. So I decided to use reflection to complete this if... else.
Because if... The judgment in else is whether the level of the audit suggestion form for the current document is equal to the level corresponding to the field of SpecialPrintModel. If so, the corresponding name will be written in the corresponding field. Decide to change the SpecialPrintModel class.

Get your hands on version 2


public class ShipSpecialPrintModel
  {
    /// <summary>
    ///  Supplier commitment 
    /// </summary>
    public string SupplierUnderTaker { get; set; }

    /// <summary>
    ///  Customer order Number 
    /// </summary>
    public string CustomerSerialNumber { get; set; }
    
    /// <summary>
    ///  The payment amount 
    /// </summary>
    public decimal PayAmount { get; set; }

    /// <summary>
    ///  Where it is 
    /// </summary>
    public string OpeningBank { get; set; }

    /// <summary>
    ///  Receiving unit 
    /// </summary>
    public string CollectionMonad { get; set; }

    /// <summary>
    ///  A bank account 
    /// </summary>
    public string BankAccount { get; set; }

    /// <summary>
    ///  agent 
    /// </summary>
    public string ResponseiblePerson { get; set; }

    /// <summary>
    ///  In charge of the leadership 
    /// </summary>
    [LevelAttribute(Level = 1)]
    public string Leader { get; set; }

    /// <summary>
    ///  Financial audit 
    /// </summary>
     [LevelAttribute(Level = 2)]
    public string FinanceApproval { get; set; }

    /// <summary>
    ///  Financial Manager audit 
    /// </summary>
     [LevelAttribute(Level = 3)]
    public string FinanceManagerApproval { get; set; }

    /// <summary>
    ///  Audit by Financial Controller 
    /// </summary>
     [LevelAttribute(Level = 4)]
    public string FinanceDirectorApproval { get; set; }

    /// <summary>
    /// CEO audit 
    /// </summary>
     [LevelAttribute(Level = 5)]
    public string CEOApproval { get; set; }

    /// <summary>
    ///  Serial number 
    /// </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);
     } 
    });
 })

However, propertyInfos basically needs to reflect to find the next element every time, in order to avoid such a performance cost, we decided to change the first flip and define a dictionary to store the fields of SpecialPrintModel's feature class.

Get your hands on version 3


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);
              }
          });

In general, if has been avoided after 3 revisions. else's code. In this case, it is also appropriate to print the name of the CTO audit, for example. Then you just need to fill in the fields in the Model class and add a special effect to the fields.

conclusion

As my colleague says, just think about it and knock a few times. Some problems are not problems. Well, let's call it a day. Good night everyone!

Please take the time to share this article with your friends or leave a comment. We will sincerely thank you for your support!


Related articles: