所謂操做日誌,就是某人對指定模塊的指定對象進行操做的記錄,在某種狀況下,可能會有顯示本次操做對哪些數據字段進行啦了動,或者是操做先後該模型的數據比對狀況。針對於這類需求,想要查看某條操做記錄具體改動項信息的時候,對於前端來說,他不須要知道這個對象的具體類型及各個字段的意義的漢字描述,他們只須要循環遍歷,將全部的數據拼到一個div容器裏便可。後臺該如何去設計才能作到最簡化的操做那?第一種狀況能夠用枚舉的形式,來標記每種模型的類型,在每次記錄日誌的時候,能夠將當前枚舉也記錄進去(數據庫/nosql),這樣的話,在查看每種記錄變更的詳情時,就能夠根據每種類型封裝不一樣的拼接數據的策略,最終以統一的格式返回給前端。可是,這種操做起來並非很理想,沒實現一種模塊的操做都要實現對應的表單項拼接策略,顯然之後維護起來並非十分的完美。那麼,能不能經過反射的形式來根絕具體的模型名稱動態的獲取模型類型,並根據具體的類型和json數據來造成對象,從而完成表單項的構建那??答案是:能夠的(c#中能夠根據Type type = Type.GetType(FullTypeName);類實現)。下面咱們就先實現一下獲取當前操做模型具體操做操做記錄。前端
1.前端須要展現成這樣:sql
2.後臺代碼設置數據庫
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ConsoleApp1.OpearorLog.Entity 9 { 10 public class ColumnRenark : Attribute 11 { 12 /// <summary> 13 /// 字段名稱 14 /// </summary> 15 public string ColumnName { get; set; } 16 /// <summary> 17 /// 字段類型 18 /// </summary> 19 public ColumnType ColumnType { get; set; } 20 21 22 public ColumnRenark() { } 23 } 24 public enum ColumnType 25 { 26 [Description("基礎類型(int/string...)")] 27 Basic = 0, 28 [Description("類類型")] 29 Class = 1, 30 [Description("字典類型")] 31 Dic = 2, 32 [Description("列表類型")] 33 Lst = 3, 34 35 36 } 37 }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp1.OpearorLog.Entity { /// <summary> ///行記錄 /// </summary> public class RowRecord { /// <summary> /// 字段語義 /// </summary> public string Key { get; set; } /// <summary> /// 字段對應值 /// </summary> public string Value { get; set; } /// <summary> /// 所屬層級 /// </summary> public int Lev { get; set; } /// <summary> /// 包含的子項 /// </summary> public List<List<RowRecord>> Child { get; set; } public RowRecord() { Child = new List<List<RowRecord>>(); } } }
1 using Newtonsoft.Json; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Runtime.InteropServices; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace ConsoleApp1 10 { 11 public class OperatorLogContext 12 { 13 #region attr 14 private List<RowRecord> RowRecords { get; set; } 15 private object Obj { get; set; } 16 public string FullTypeName { get; set; } 17 public string JsonStr { get; set; } 18 #endregion 19 20 public OperatorLogContext(string fullTypeName,string jsonStr) 21 { 22 FullTypeName = fullTypeName; 23 JsonStr = jsonStr; 24 RowRecords = new List<RowRecord>(); 25 Type type = Type.GetType(FullTypeName); 26 Obj = JsonConvert.DeserializeObject(JsonStr,type); 27 } 28 public OperatorLogContext() 29 { 30 Type type = Type.GetType(FullTypeName); 31 Obj = JsonConvert.DeserializeObject(JsonStr, type); 32 } 33 /// <summary> 34 /// 構建表單項 35 /// </summary> 36 /// <returns></returns> 37 public List<RowRecord> BuildForm() 38 { 39 return Build(Obj); 40 } 41 #region private 42 private List<RowRecord> Build(object obj, RowRecord parentRow = null, List<RowRecord> childRow = null, int lev = 0) 43 { 44 //1.當前類型 45 Type currentType = obj.GetType(); 46 //2.獲取當下模型的全部屬性字段 47 var props = currentType.GetProperties(); 48 foreach (var prop in props) 49 { 50 RowRecord rowRecord = new RowRecord(); 51 rowRecord.Lev = lev; //設置當前樹形級別 52 //3.獲取當下屬性字段下的全部自定義屬性 53 var attr = prop.CustomAttributes.FirstOrDefault(o => o.AttributeType == typeof(ColumnRenark)); 54 if (attr == null) 55 { 56 continue; 57 } 58 else 59 { 60 foreach (var named in attr.NamedArguments) 61 { 62 if (named.MemberName == "ColumnName") 63 { 64 rowRecord.Key = named.TypedValue.Value.ToString(); 65 } 66 else if (named.MemberName == "ColumnType") 67 { 68 ColumnType columnType = (ColumnType)Enum.Parse(typeof(ColumnType), named.TypedValue.Value.ToString()); 69 switch (columnType) 70 { 71 case ColumnType.Basic: 72 rowRecord.Value = prop.GetValue(obj).ToString(); 73 break; 74 case ColumnType.Class: 75 Build(prop.GetValue(obj), rowRecord, new List<RowRecord>()); 76 break; 77 case ColumnType.Lst: 78 var currentLst = (IEnumerable<object>)prop.GetValue(obj); 79 80 foreach (var opt in currentLst) 81 { 82 83 Build(opt, rowRecord, new List<RowRecord>()); 84 } 85 break; 86 } 87 } 88 } 89 } 90 91 if (parentRow != null) 92 { 93 rowRecord.Lev = parentRow.Lev + 1; 94 childRow.Add(rowRecord); 95 } 96 else 97 { 98 RowRecords.Add(rowRecord); 99 } 100 } 101 if (childRow != null) 102 { 103 parentRow.Child.Add(childRow); 104 } 105 return RowRecords; 106 } 107 #endregion 108 109 } 110 }
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Text; namespace ConsoleApp1 { class Program { static void Main(string[] args) { User user = new User(); user.Age = 20; user.Name = "lsh"; user.Book = new Book() { Name = "c#從入門指南", Desc = "書籍描述" }; user.Hobby = new List<Hobby>() { new Hobby() { Name = "讀書", Rate = "89%" }, new Hobby() { Name = "旅遊", Rate = "33%" } }; string json = JsonConvert.SerializeObject(user); var lst = new OperatorLogContext("ConsoleApp1.User", json).BuildForm(); Console.ReadKey(); } } public class User { [ColumnRenark(ColumnName = "姓名", ColumnType = ColumnType.Basic)] public string Name { get; set; } [ColumnRenark(ColumnName = "年齡", ColumnType = ColumnType.Basic)] public int Age { get; set; } [ColumnRenark(ColumnName = "書籍", ColumnType = ColumnType.Class)] public Book Book { get; set; } [ColumnRenark(ColumnName = "愛好", ColumnType = ColumnType.Lst)] public List<Hobby> Hobby { get; set; } } public class Hobby { [ColumnRenark(ColumnName = "愛好名", ColumnType = ColumnType.Basic)] public string Name { get; set; } [ColumnRenark(ColumnName = "比率", ColumnType = ColumnType.Basic)] public string Rate { get; set; } } /// <summary> /// 行元素 /// </summary> public class RowRecord { public string Key { get; set; } public string Value { get; set; } public int Lev { get; set; } public List<List<RowRecord>> Child { get; set; } public RowRecord() { Child = new List<List<RowRecord>>(); } } public class Book { [ColumnRenark(ColumnName = "書名", ColumnType = ColumnType.Basic)] public string Name { get; set; } [ColumnRenark(ColumnName = "書描述", ColumnType = ColumnType.Basic)] public string Desc { get; set; } } /// <summary> /// 字段標記屬性 /// </summary> public class ColumnRenark : Attribute { /// <summary> /// 字段名稱 /// </summary> public string ColumnName { get; set; } /// <summary> /// 字段類型 /// </summary> public ColumnType ColumnType { get; set; } public ColumnRenark() { } } public enum ColumnType { [Description("基礎類型(int/string...)")] Basic = 0, [Description("類類型")] Class = 1, [Description("字典類型")] Dic = 2, [Description("列表類型")] Lst = 3, } }