日誌本地化工具

    程式設計師討厭寫文檔, 討厭寫注釋, 而我還討厭寫日誌, 輸出一個  “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"}

    業務部門的人就是看不懂, 畢竟不是人人都有良好的英語基礎, 同時我也經常猜不到有人用  DRLS 表示 “當日流水”.

    其實如果只要稍微把 json 裡面的key 用中文替代, 業務部門還是能大概讀得懂大部分意思的.

    所以我開發了一個工具  LocalizationTools, 協助生成中文日誌.

    新建一個 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,
    }

View Code

 

   記得在生成介面勾上 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, 布爾值在不同的場景可以表示:  是/否、對/錯、啟用/關閉……. 業務人員可不想自己猜, 解決辦法有兩個

    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, 它的優先順序也比 注釋里的summary 高

 

     這裡特彆強調一下,  LocalizationTools.ToString() 不是一個Json 序列化工具, 為了使用隨處可見的 Json格式化工具, 而將輸出調整得像Json, 所以這個工具從來就沒有考慮到反序列化功能, 也沒有去解決循環引用的問題, 也沒有考慮到要符合Json 的標準, 僅僅是一個方便輸出中文日誌的工具, 也沒有追求高性能.

     LocalizationTools.ToString() 特別適用於面向數據表的編程, 因為表欄位一般都是簡單的類型, 輸出的日誌更為直觀.

     按理說應該為這個工具提供擴展方法, 但是我有強迫症, 許多類庫給 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);
        }
    }
}

View Code

 

 

     新增實體的日誌解決了, 接下來又有另一個問題, 如何保存實體變化的日誌?

     最簡單的辦法就是把 實體類 修改前的json 和 修改後的json 都保存起來, 讓業務人員自己去痛苦尋找的變化, 呵呵呵, 只要是個人, 都會抱怨.

     讓程式設計師一個欄位一個欄位的比較, 然後生成日誌, 開玩笑! 我干不來這樣枯燥的活

     nuget 上有 JsonDiffPatch 這樣的工具生成 JSON patch, 但輸出的結果就不是為人類準備的, 所以我又繼續寫了 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 修改裡面的比較結果, 最後再得出比較結果.

 

 

 

end

 

Tags: