C# 開發(fā)日志本地化工具
程序員討厭寫文檔, 討厭寫注釋, 而我還討厭寫日志, 輸出一個 "Id=5, 姓名=王大錘, 性別=男, 生日=2020年1月1日" 總歸會用到字符串的填充
var log = $"Id={person.Id}, 姓名={person.Name}, 性別={(person.Sex == SexType.Man ? "男性" : "女性")}, 生日={person.Birthday}";
Json序列化工具多好啊, 可是輸出的是
{"id": 5,"name":"葫蘆娃", "sex":"Man", "birthday":"2020-1-1 00:00:00"}
業(yè)務部門的人就是看不懂, 畢竟不是人人都有良好的英語基礎, 同時我也經常猜不到有人用 DRLS 表示 "當日流水".
其實如果只要稍微把 json 里面的key 用中文替代, 業(yè)務部門還是能大概讀得懂大部分意思的.
所以我開發(fā)了一個工具 LocalizationTools, 協(xié)助生成中文日志.
新建一個 Console, 引入 nuget 包: LocalizationTools, 然后定義示例類
/// <summary> /// 人類 /// </summary> public class Person { /// <summary> /// Id /// </summary> public int Id { get; set; } /// <summary> /// 名字 /// </summary> public string Name { get; set; } /// <summary> /// 出生日期, 出生日期最好不要超過當前時間 /// </summary> [DisplayName("出生日期")] public DateTime Birthday { get; set; } /// <summary> /// 性別 /// </summary> public SexType Sex { get; set; } /// <summary> /// 是否活著 /// </summary> public bool IsAlive { get; set; } } /// <summary> /// 性別 /// </summary> public enum SexType { /// <summary> /// 男性 /// </summary> Man = 0, /// <summary> /// 女性 /// </summary> Woman = 2, /// <summary> /// 人妖 /// </summary> Ladyman = 3, }
記得在生成界面勾上 XML文檔文件
使用代碼
static void Main(string[] args) { var p1 = new Person { Id = 1, Name = "王大錘", Birthday = DateTime.Parse("2020-01-01"), Sex = SexType.Man, }; LocalizationTools.KeyValueSeparator = "="; var str = LocalizationTools.ToString(p1); Console.WriteLine(str); }
相信這樣的輸出, 大部分人也應該能夠看懂了
{"Id"=1,"名字"="王大錘","出生日期"="2020/1/1 0:00:00","性別"="男性","是否活著"=false}
LocalizationTools.ToString() 方法會將 屬性名稱 替換成注釋里的 Summary 信息, 枚舉值也同樣會進行這樣的替換
如果字段很少, 剛才的輸出還沒什么問題, 如果字段非常多, 讀著就眼花繚亂了, 所以我建議還是這行刪除
LocalizationTools.KeyValueSeparator = "=";
這樣輸出的內容是
{"Id":1,"名字":"王大錘","出生日期":"2020/1/1 0:00:00","性別":"男性","是否活著":false}
使用Json工具格式化一下
{ "Id": 1, "名字": "王大錘", "出生日期": "2020/1/1 0:00:00", "性別": "男性", "是否活著": false }
這樣即使包含了子對象的對象, 也非常清晰明了了.
這里面的不足是: "是否活著" 這個屬性輸出的是 true/false, 布爾值在不同的場景可以表示: 是/否、對/錯、啟用/關閉....... 業(yè)務人員可不想自己猜, 解決辦法有兩個
1. 在ToString()前, 我知道IsAlive是false, 應該用 "否" 來替換
var str = LocalizationTools.ToString(p1, new { IsAlive = "否" }); // 輸出 {"Id":1,"名字":"王大錘","出生日期":"2020/1/1 0:00:00","性別":"男性","是否活著":"否"}
2. 給 IsAlive 屬性加上 ToStringReplacePairAttribute, 來替換某些特定的值
[ToStringReplacePair(true, "是", false, "否")] public bool IsAlive { get; set; }
LocalizationTools 替換 屬性名稱 的順序是 1. DisplayNameAttribute 2. 注釋里的summary, 因為有些人喜歡在 summary 中加入其他說明信息, 輸出到日志里不好看;
由于 DisplayNameAttribute 不能作用于 enum枚舉值, 所以我專門定義了 EnumAliasAttribute, 它的優(yōu)先級也比 注釋里的summary 高
這里特別強調一下, LocalizationTools.ToString() 不是一個Json 序列化工具, 為了使用隨處可見的 Json格式化工具, 而將輸出調整得像Json, 所以這個工具從來就沒有考慮到反序列化功能, 也沒有去解決循環(huán)引用的問題, 也沒有考慮到要符合Json 的標準, 僅僅是一個方便輸出中文日志的工具, 也沒有追求高性能.
LocalizationTools.ToString() 特別適用于面向數(shù)據表的編程, 因為表字段一般都是簡單的類型, 輸出的日志更為直觀.
按理說應該為這個工具提供擴展方法, 但是我有強迫癥, 許多類庫給 object 加上了各種擴展方法, 讓我很不爽, 所以我沒有在類庫中主動加入擴展方法, 大家可以在自己的項目里加入以下代碼, 以提供擴展方法
namespace Localization { using System.Collections.Generic; public static class LocalizationToolsExtend { public static string ToLocalizationString(this object obj, params string[] ignorePropertyNames) { return LocalizationTools.ToString(obj, ignorePropertyNames); } public static string ToLocalizationString<T>(this object obj, T customPropertyValues, params string[] ignorePropertyNames) where T : class { return LocalizationTools.ToString(obj, customPropertyValues, ignorePropertyNames); } public static string ToLocalizationString(this object obj, Dictionary<string, object> customPropertyValues, params string[] ignorePropertyNames) { return LocalizationTools.ToString(obj, customPropertyValues, ignorePropertyNames); } public static string ToLocalizationStringInclude(this object obj, IEnumerable<string> includePropertyNames) { return LocalizationTools.ToStringInclude(obj, includePropertyNames); } public static string ToLocalizationStringInclude<T>(this object obj, IEnumerable<string> includePropertyNames, T customPropertyValues) where T : class { return LocalizationTools.ToStringInclude(obj, includePropertyNames, customPropertyValues); } public static string ToLocalizationStringInclude(this object obj, IEnumerable<string> includePropertyNames, Dictionary<string, object> customPropertyValues) { return LocalizationTools.ToStringInclude(obj, includePropertyNames, customPropertyValues); } } }
新增實體的日志解決了, 接下來又有另一個問題, 如何保存實體變化的日志?
最簡單的辦法就是把 實體類 修改前的json 和 修改后的json 都保存起來, 讓業(yè)務人員自己去痛苦尋找的變化, 呵呵呵, 只要是個人, 都會抱怨.
讓程序員一個字段一個字段的比較, 然后生成日志, 開玩笑! 我干不來這樣枯燥的活
nuget 上有 JsonDiffPatch 這樣的工具生成 JSON patch, 但輸出的結果就不是為人類準備的, 所以我又繼續(xù)寫了 Compare 方法
static void Main(string[] args) { var p1 = new Person { Id = 1, Name = "王大錘", Birthday = DateTime.Parse("2020-01-01"), Sex = SexType.Man, }; var p2 = new Person { Id = 1, Name = "王小錘", Birthday = DateTime.Parse("2021-01-01"), Sex = SexType.Man, }; var compareResult = LocalizationTools.Compare(p1, p2); Console.WriteLine(compareResult.GetDifferenceMsg()); } // 輸出: {"名字":{"從":"王大錘","變成":"王小錘"},"出生日期":{"從":"2020/1/1 0:00:00","變成":"2021/1/1 0:00:00"}}
Json格式化一下
{ "名字": { "從": "王大錘", "變成": "王小錘" }, "出生日期": { "從": "2020/1/1 0:00:00", "變成": "2021/1/1 0:00:00" } }
當然你可以對 CompareResult 進行進一步處理, 使用 UpdateDifferentProperty 修改里面的比較結果, 最后再得出比較結果.
以上就是C# 開發(fā)日志本地化工具的詳細內容,更多關于C# 日志本地化工具的資料請關注腳本之家其它相關文章!
- 基于c# Task自己動手寫個異步IO函數(shù)
- C#異步方法返回void與Task的區(qū)別詳解
- 深入分析C#中的異步和多線程
- c# winform異步不卡界面的實現(xiàn)方法
- C#用委托BeginInvoke做異步線程
- C#中一個高性能異步socket封裝庫的實現(xiàn)思路分享
- C#實現(xiàn)異步編程的方法
- c#中Winform實現(xiàn)多線程異步更新UI(進度及狀態(tài)信息)
- c# 用Dictionary實現(xiàn)日志數(shù)據批量插入
- c# 用ELMAH日志組件處理異常
- C#使用SqlServer作為日志數(shù)據庫的設計與實現(xiàn)
- C#打印日志的方法總結
- c#快速寫本地日志方法
- C#中四步輕松使用log4net記錄本地日志的方法
- c# 編寫一個輕量級的異步寫日志的實用工具類(LogAsyncWriter)