C# 开发日志本地化工具

作者:zhouandke 时间:2023-08-27 21:57:05 

    程序员讨厌写文档, 讨厌写注释, 而我还讨厌写日志, 输出一个  "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,
 }

   记得在生成界面勾上 XML文档文件

C# 开发日志本地化工具

      使用代码


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);
   }
 }
}

     新增实体的日志解决了, 接下来又有另一个问题, 如何保存实体变化的日志?

     最简单的办法就是把 实体类 修改前的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 修改里面的比较结果, 最后再得出比较结果.

来源:https://www.cnblogs.com/zhouandke/p/14342779.html

标签:c#,日志,本地化,工具
0
投稿

猜你喜欢

  • Android 高仿微信朋友圈动态支持双击手势放大并滑动查看图片效果

    2021-08-21 21:16:40
  • springboot拦截器Interceptor的使用,你都了解吗

    2023-01-01 21:53:40
  • Android解析json数组对象的方法及Apply和数组的三个技巧

    2023-04-11 11:52:56
  • 详解SpringMVC使用MultipartFile实现文件的上传

    2023-03-28 00:48:18
  • IntelliJ IDEA各种图标的含义

    2022-08-12 21:50:25
  • Android开发之MediaPlayer基本使用方法详解

    2022-09-05 12:21:38
  • java 生成有序账号的实现方法

    2023-08-12 03:28:01
  • 老生常谈Java反射机制(必看篇)

    2023-09-02 22:20:06
  • Java Idea高效率配置技巧实例解析

    2023-06-05 13:24:42
  • Java实现简单班级管理系统

    2023-01-07 16:20:29
  • java泛型常用通配符实例解析

    2022-09-16 22:14:50
  • Android系统音量条实例代码

    2022-05-26 15:20:48
  • spring boot 2.x html中引用css和js失效问题及解决方法

    2021-08-13 10:28:32
  • C#控制台程序中使用官方依赖注入的实现

    2021-07-12 15:35:09
  • Android通过JNI实现守护进程

    2021-11-24 20:38:02
  • Java中super和this关键字详解

    2023-03-18 15:49:08
  • unity3d实现七天签到功能

    2023-01-05 08:57:21
  • Activiti7整合Springboot使用记录

    2022-11-11 06:17:24
  • spring mvc4中相关注解的详细讲解教程

    2021-10-11 23:21:17
  • 在Winform框架界面中改变并存储界面皮肤样式的方法

    2021-06-08 09:08:24
  • asp之家 软件编程 m.aspxhome.com