.NET架构小技巧(4)——反射,架构人员法宝II
上一篇博文中,利用屬性反射的特點,用兩個方法完成了字符轉實體,實體轉字符的工作,但有些復雜的場景,上面方法就沒那么好用了,就需要更復雜的方式來組裝處理。
先來看一個接口文檔,下面是接口的調用方式
long OltpTransData(unsigned long msgType,unsigned long packageType,unsigned?long?packageLength,char?*str,LPTSTR?com);I.msgType:業務請求類型;
II.packageType:數據解析格式類型,系統重組數據時使用
III.packageLength:數據串的長度;
IV.?str:數據串;調用時,通過數據串傳入參數;函數返回時,數據串中包含返回的數據,數據按字符串方式組合,并且在字符串第一位保留一個空格;另外,除了16位日期右補空格,其他的字段均以左空格補位
V.?com:數據請求串口
業務請求類型 | 數據解析格式類型 | 數據串最小長度 | 說明 |
1001 | 101 | 126 | 實時驗卡(讀卡、驗卡) |
1002 | 12 | 610 | 實時結算 |
1003 | 7 | 291 | 實時明細數據傳輸 |
1004 | 9 | 253 | 實時住院登記數據傳輸 |
1005 | 8 | 309 | 實時醫囑數據傳輸 |
1006 | 12 | 610 | 實時結算預算 |
1007 | 2 | 1101 | 實時住院首次病程記錄傳輸 |
1009 | 504 | 85 | 醫師信息查詢 |
1010 | 510 | 331 | 出入院標準傳輸 |
讀卡
序號 | 定義 | 數據原型 | 起始位置 | 數據長度 | 備注 | 數據填充 |
1 | 個人編號 | CHAR | 1 | 8 | 醫保編號,以’E’開頭的為異地社保卡,詳見說明 | 院端 |
2 | 姓名 | CHAR | 9 | 20 | 中心 | |
3 | 身份證號 | CHAR | 29 | 18 | 18位或15位 | 中心 |
4 | IC卡號 | CHAR | 47 | 9 | 院端 | |
5 | 治療序號 | NUM | 56 | 4 | 中心 | |
6 | 職工就醫類別 | CHAR | 60 | 1 | A在職、B退休、L事業離休、T特診、Q企業離休、E退老、N農民工、X未成年居民、O老年居民(老年居民、低收入人員、殘疾人)、D低保人員、S ?三無人員、U 大學生 | 中心 |
7 | 基本個人帳戶余額 | NUM | 61 | 10 | 中心 | |
8 | 補助個人帳戶余額 | NUM | 71 | 10 | 現用于公務員單獨列帳 | 中心 |
9 | 統籌累計 | NUM | 81 | 10 | 中心 | |
10 | 門診慢病統籌累計 | NUM | 91 | 10 | 中心 | |
11 | 月繳費基數 | NUM | 101 | 10 | 月繳費工資 | 中心 |
12 | 帳戶狀態 | CHAR | 111 | 1 | A正常、B半止付、C全止付、D銷戶 | 中心 |
13 | 參保類別1 | CHAR | 112 | 1 | 是否享受高額: 0 不享受高額、1 ?享受高額、2 醫療保險不可用 | 中心 |
14 | 參保類別2 | CHAR | 113 | 1 | 是否享受補助(商業補助、公務員補助):0 ?不享受、1 商業、2 ?公務員、3事業離休差額撥款人員 | 中心 |
15 | 參保類別3 | CHAR | 114 | 1 | 0 企保、1 事保、2企業慢病、3事業慢病、4異地就醫,詳見說明 | 中心 |
16 | 參保類別4 | CHAR | 115 | 1 | 0或2生育不可用、1或3生育可用 | 中心 |
17 | 參保類別5 | CHAR | 116 | 1 | 0工傷不可用、1工傷可用 | 中心 |
18 | 住院次數累計 | NUM | 117 | 4 | 中心 | |
19 | 家床次數累計 | NUM | 121 | 4 | 中心 |
查詢醫師
序號 | 定義 | 數據原型 | 起始位置 | 數據長度 | 備注 | 填寫方式 |
1 | 醫師編碼 | CHAR | 1 | 8 | 院端 | |
2 | 醫師姓名 | CHAR | 9 | 20 | 中心 | |
3 | 身份證號 | CHAR | 29 | 18 | 中心 | |
4 | 可出診醫院編號 | CHAR | 47 | 20 | 詳見說明 | 中心 |
5 | 終止日期 | DATETIME | 67 | 16 | YYYYMMDDHHMMSS | 中心 |
6 | 有效標志 | CHAR | 83 | 1 | ‘0’無效,‘1’有效 | 中心 |
這個接口是拼接方式,每個數據項都有固定的長度,有些數據也有固定的格式,比如日期,還有很多類型,都是有固定值固定含義的。這種情況下需要更多的信息來告訴兩個轉換方法該怎么轉換,這里就引出了Attribute——一個專門來給類或屬性方法加特征的知識點。
/// <summary>/// 發送報文類型/// </summary>[AttributeUsage(AttributeTargets.Class)]public class PackageTypeAttribute : Attribute{/// <summary>/// 發關報文實體類屬性特性類/// </summary>/// <param name="SN">屬性的序號,從1開始</param>/// <param name="Length">屬性轉成字符串后長度</param>public PackageTypeAttribute(uint OperationType, uint DataFormaterType, uint MinLength){this.OperationType = OperationType;this.DataFormaterType = DataFormaterType;this.MinLength = MinLength;}/// <summary>/// 業務請求類型/// </summary>public uint OperationType{ get; private set; }/// <summary>/// 數據解析格式類型/// </summary>public uint DataFormaterType{ get; private set; }/// <summary>/// 數據串最小長度/// </summary>public uint MinLength{ get; private set; }}/// <summary>/// 報文中屬性的順序SN和長度Length/// </summary>[AttributeUsage(AttributeTargets.Property)]public class PackageAttribute : Attribute{/// <summary>/// 序號,從1開始/// </summary>public int SN{ get; private set; }/// <summary>/// 轉成字符串后的長度/// </summary>public int Length{ get; private set; }/// <summary>/// 發關報文實體類屬性特性類/// </summary>/// <param name="SN">屬性的序號,從1開始</param>/// <param name="Length">屬性轉成字符串后長度</param>public PackageAttribute(int SN, int Length){this.SN = SN;this.Length = Length;}/// <summary>/// 是否是時間類型,因為時間類型是左對齊,右補空格/// </summary>public bool IsDateTime{ get; set; }}/// <summary>/// 取枚舉的值還是/// </summary>[AttributeUsage(AttributeTargets.Enum)]public class EnumValeuNumberAttribute : Attribute{/// <summary>/// 是否把枚舉類型屬性的的值數轉成Char類型/// </summary>public bool IsChar{ get; set; }}定義了三個特性類,PackageTypeAttribute主用來區分不同的交易類型,從實體類上獲取不同交易的函數參數;PackageAttribute是在實體類的屬性上的,是核心特性類,它標記了屬性的序號,和每個屬性的長度,和屬性是否是DateTime類型;EnumValeuNumberAttribute是用來專門處理枚舉類型的屬性的。
/// <summary>/// 醫師信息查詢/// </summary>[PackageType(1009, 504, 85)]public class DoctorQuery : Entity{/// <summary>/// 醫師編碼/// </summary>[Package(1, 8)]public virtual String DoctorCode{get; set;}/// <summary>/// 醫師姓名/// </summary>[Package(2, 20)]public virtual String DoctorName{ get; set; }/// <summary>/// 身份證號/// </summary>[Package(3, 18)]public virtual string PersonID{ get; set; }///編號為0002的醫院, 下屬有編號為0113的定點, 在總院注冊登記的醫師可以在這樣的2家醫院出診, 則“可出診醫院編號”為00020113,若長度不足20位則前補空格。/// <summary>/// 可出診醫院編號/// </summary>[Package(4, 20)]public virtual string CanVisitHospitalCode{ get; set; }/// <summary>/// 終止日期/// </summary>[Package(5, 16, IsDateTime = true)]public virtual string TerminationTime{ get; set; }/// <summary>/// 有效標志/// </summary>[Package(6, 1)]public virtual DLYBAvailableMarker DLYBAvailableMarker{ get; set; }}/// <summary>/// 有效標志/// </summary>[EnumValeuNumber]public enum DLYBAvailableMarker{/// <summary>/// 無效/// </summary>nullity = 0,/// <summary>/// 有效/// </summary>Valid = 1}/// <summary>/// 實時驗卡(讀卡、驗卡)/// </summary>[PackageType(1001, 101, 126)] public class QueryCardEntity : Entity{ /// <summary>/// 個人編號/// </summary>[Package(1, 8)]public virtual string PersonNumber{ get; set; }/// <summary>/// 姓名/// </summary>[Package(2, 20)]public virtual string Name{ get; set; }/// <summary>/// 身份證號/// </summary>[Package(3, 18)]public virtual string PersonID{ get; set; }/// <summary>/// IC卡號/// </summary>[Package(4, 9)]public virtual string ICCardNumber{ get; set; }long therapyNumber;/// <summary>/// 治療序號/// </summary>[Package(5, 4)]public virtual long TherapyNumber{get{return therapyNumber;}set{if (value >= 0 && value <= 9999){therapyNumber = value;}else{throw new Exception("治療號在0-9999之間");}}}/// <summary>/// 職工就醫類別/// </summary>[Package(6, 1)]public virtual string TherapyCategory{ get; set; }/// <summary>/// 基本個人帳戶余額/// </summary>[Package(7, 10)]public virtual decimal BasePersonBalance{ get; set; }/// <summary>/// 補助個人帳戶余額/// </summary>[Package(8, 10)]public virtual decimal SubsidyPersonBalance{ get; set; }/// <summary>/// 統籌累計/// </summary>[Package(9, 10)]public virtual decimal PlannerTotal{ get; set; }/// <summary>/// 門診慢病統籌累計///新/// </summary>[Package(10, 10)]public virtual decimal MZSlowDisease{ get; set; }/// <summary>/// 月繳費基數/// </summary>[Package(11, 10)]public virtual decimal BaseFeeByMonth{ get; set; }/// <summary>/// 帳戶狀態/// </summary>[Package(12, 1)]public virtual string AccoutState{ get; set; }/// <summary>/// 參保類別1/// </summary>[Package(13, 1)]public virtual string InsuranceCategory1{ get; set; }/// <summary>/// 參保類別2/// </summary>[Package(14, 1)]public virtual string InsuranceCategory2{ get; set; }/// <summary>/// 參保類別3/// </summary>[Package(15, 1)]public virtual string InsuranceCategory3{ get; set; }/// <summary>/// 參保類別4/// </summary>[Package(16, 1)]public virtual string InsuranceCategory4{ get; set; }/// <summary>/// 參保類別5/// </summary>[Package(17, 1)]public virtual string InsuranceCategory5{ get; set; }/// <summary>/// 住院次數累計新/// </summary>[Package(18, 4)]public virtual int ZYAddNumber{ get; set; }/// <summary>/// 家床次數累計新/// </summary>[Package(19, 4)]public virtual int AddBedNumber{ get; set; }}上面的實體類分別使用了特性類,參照文檔就OK。
?上面代碼是對某些屬性的對齊方式作了處理。
這兩個方法核心里通過反射屬性上的特性,取特性中定義的固定值,來生成接口要求的字符串,合理的設計特性,可以使兩個轉換方法更優雅,更簡便,在開發過程中,也需要不斷調整理,適配,逐漸完善。
可以用下面的代碼完成測試
using?System; namespace ArchitectureDemo04 {class Program{static void Main(string[] args){var backQueryCard = Send(new QueryCardEntity { PersonNumber = "0000001", ICCardNumber = "C00000001" });var backDoctorQuery = Send(new DoctorQuery { DoctorCode = "0001" });}/// <summary>/// 發送/// </summary>/// <param name="entity"></param>/// <returns></returns>static Entity Send(Entity entity){try{foreach (var att in entity.GetType().GetCustomAttributes(false)){if (att is PackageTypeAttribute){var attPackage = att as PackageTypeAttribute; Console.WriteLine($"入參:");Console.WriteLine(entity);Console.WriteLine("模擬函數調用:");Console.WriteLine($"OltpTransData({attPackage.OperationType},{attPackage.DataFormaterType},{attPackage.MinLength},{entity})");var backContent = BackOperation(entity);var backEntity = entity.ToEntity(entity.GetType(),backContent);return backEntity;}}return null;}catch{throw;}}/// <summary>/// 模擬醫保中心返回/// </summary>/// <param name="entity">參數</param>/// <returns></returns>static string BackOperation(Entity entity){switch (entity.GetType().Name){case "QueryCardEntity":return " 0000001 Jack210213198411113111C00000001 1A 1000.66 0 0 0 1800A00131 0 0"; case "DoctorQuery":return " 0001 DcotorLi210211198707182233 0002011320201029190850 1";}return null;}} }總結
以上是生活随笔為你收集整理的.NET架构小技巧(4)——反射,架构人员法宝II的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 译 | 将数据从Cosmos DB迁移到
- 下一篇: .NET架构小技巧(5)——反射,架构人