日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

.NET架构小技巧(4)——反射,架构人员法宝II

發布時間:2023/12/4 asp.net 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .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。

public static class StringExtension{ /// <summary>/// 右邊不夠長度補空格,漢字算兩個空格/// </summary>/// <param name="str"></param>/// <param name="length">設定長度</param>/// <returns></returns>public static string ChineseCharacterLeft(this string str, int length){var len = Encoding.Default.GetBytes(str).Length;if (len < length){for (int i = 0; i < length - len; i++){str = " " + str;}}return str;}/// <summary>/// 右邊不夠長度補空格,漢字算兩個空格/// </summary>/// <param name="str"></param>/// <param name="length">設定長度</param>/// <returns></returns>public static string ChineseCharacterRight(this string str, int length){var len = Encoding.Default.GetBytes(str).Length;if (len < length){for (int i = 0; i < length - len; i++){str += " ";}}return str;}/// <summary>/// 切除字符串/// </summary>public static string ChineseCharacterSubstring(this string str, int length, out string remaining){var arr = Encoding.Default.GetBytes(str);var barr = arr.Take(length).ToArray();var valuestr = Encoding.Default.GetString(barr);barr = arr.Skip(length).ToArray();remaining = Encoding.Default.GetString(barr); ;return valuestr;}}

?上面代碼是對某些屬性的對齊方式作了處理。

/// <summary>/// 報文類的父類/// </summary>public abstract class Entity{/// <summary>/// 組裝發送報文格式/// </summary>/// <returns></returns>public override string ToString(){var pros = this.GetType().GetProperties();var sortPro = new SortedList<int, PropertyInfo>(); foreach (var pro in pros){foreach (var att in pro.GetCustomAttributes(false)){if (att is PackageAttribute){var packageAtt = att as PackageAttribute; sortPro.Add(packageAtt.SN, pro);}}}var content = new StringBuilder();#region 組合發送字符串//遍歷屬性 foreach (var pro in sortPro){//遍歷屬性上的特性 foreach (var att in pro.Value.GetCustomAttributes(false)){//判斷是否為自定義的PackageAttribute類型if (att is PackageAttribute){//轉換屬性上的特性類var packageAtt = att as PackageAttribute;//取拼接時字符長度var length = packageAtt.Length;//取屬性的值var proValue = pro.Value.GetValue(this, new Object[0]);//對decimal作處理if (pro.Value.PropertyType.Name.ToLower() == "decimal"){proValue = Math.Round(Convert.ToDecimal(proValue), 2);if (Encoding.Default.GetByteCount(proValue.ToString()) > length){proValue = "0";}}//判斷字符串長度過長if (proValue != null && (pro.Value.PropertyType.Name.ToLower() == "string")){if (System.Text.Encoding.Default.GetBytes(proValue.ToString()).Length > length){throw new Exception(string.Format("屬性{0}的值{1},長度超過{2}", pro.Value.Name, proValue, length));}}//如果值為非空if (proValue != null){//日期是右補空格,其他是左補空格if (!packageAtt.IsDateTime){//這里注冊,有些屬性是枚舉類型,有些屬性拼接枚舉的值,有些取枚舉值對應的枚舉數值,這里是從該屬性類型上的EnumValeuNumberAttribute特性的IsValue屬性來判斷的,IsValue為true,就取枚舉的值,為false取該值對應的枚舉數if (pro.Value.PropertyType.IsEnum){foreach (var eatt in pro.Value.PropertyType.GetCustomAttributes(false)){if (eatt is EnumValeuNumberAttribute){var enumVaNu = eatt as EnumValeuNumberAttribute;if (enumVaNu.IsChar){var enumNumber = ((char)(int)Enum.Parse(pro.Value.PropertyType, proValue.ToString())).ToString();content.Append(enumNumber.ChineseCharacterLeft(length));}else{var enumNumber = ((int)Enum.Parse(pro.Value.PropertyType, proValue.ToString())).ToString();content.Append(enumNumber.ChineseCharacterLeft(length));}}}}else{content.Append(proValue.ToString().ChineseCharacterLeft(length));}}else//日期類型右補空格{content.Append(proValue.ToString().ChineseCharacterRight(length));}}else{content.Append("".ChineseCharacterLeft(length));}}}}#endregionreturn content.ToString();}/// <summary>/// 把一個字符串轉成一個對象/// </summary>/// <param name="content"></param>/// <returns></returns>public Entity ToEntity(Type entityType,string content){var pros = entityType.GetProperties();//按照特性類上的SN序號把屬性名存入集合proPackageList中List<PropertyInfo> proPackageList = new List<PropertyInfo>(pros.Length);//初始化屬性集合for (int i = 0; i < pros.Length; i++){foreach (var att in pros[i].GetCustomAttributes(false)){if (att is PackageAttribute){proPackageList.Add(null);break;}}}//按屬性順序排列屬性foreach (var pro in pros){foreach (var att in pro.GetCustomAttributes(false)){if (att is PackageAttribute){var packageAtt = att as PackageAttribute;var index = packageAtt.SN - 1;proPackageList[index] = pro;}}}//創建實體對象var constructor = entityType.GetConstructor(new Type[0]);var?entity?=?constructor.Invoke(new?object[0]);foreach (var pro in proPackageList){//遍歷屬性上的特性foreach (var att in pro.GetCustomAttributes(false)){//判斷是否為自定義的PackageAttribute類型if (att is PackageAttribute){//轉換屬性上的特性類var packageAtt = att as PackageAttribute;var length = packageAtt.Length;var valuestr = content.ChineseCharacterSubstring(length, out content).Trim();if (pro.PropertyType.IsEnum){foreach (var eatt in pro.PropertyType.GetCustomAttributes(false)){if (eatt is EnumValeuNumberAttribute){var eat = eatt as EnumValeuNumberAttribute;if (eat.IsChar){var chr = Convert.ToChar(valuestr);var value = Convert.ChangeType(Enum.Parse(pro.PropertyType, ((int)chr).ToString()), pro.PropertyType);pro.SetValue(entity, value, null);}else{var value = Convert.ChangeType(Enum.Parse(pro.PropertyType, valuestr), pro.PropertyType);pro.SetValue(entity, value, null);}break;}}}else{var value = Convert.ChangeType(valuestr, pro.PropertyType);pro.SetValue(entity, value, null);}}}}return (Entity)entity;}}

這兩個方法核心里通過反射屬性上的特性,取特性中定義的固定值,來生成接口要求的字符串,合理的設計特性,可以使兩個轉換方法更優雅,更簡便,在開發過程中,也需要不斷調整理,適配,逐漸完善。

可以用下面的代碼完成測試

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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。