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文档文件
使用代码
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


猜你喜欢
- 题目给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。示例 1:输入: "abcabcbb&qu
- 环境信息名称版本号Spring Boot2.4.5Idea2021.3.2服务端实现导入依赖<dependency>  
- 本文实例讲述了C#多线程与跨线程访问界面控件的方法。分享给大家供大家参考。具体分析如下:在编写WinForm访问WebService时,常会
- Java高德地图Api的使用使用高德经纬度获取地址信息一些准备用到的常量 /** *
- 使用 WebView 时,我们通常会重写以下方法:shouldOverrideUrlLoading() onPageStarted()onP
- xUtils简介xUtils 包含了很多实用的android工具。xUtils 支持大文件上传,更全面的http请求协议支持(10种谓词),
- Feign传递请求头信息在我之前的文章服务网关Spring Cloud Zuul中,将用户的登录id放在了请求头中传递给内部服务。但是当内部
- 本文实例讲述了C#实现获取不同对象中名称相同属性的方法。分享给大家供大家参考。具体如下:【两个类】class demo1{ public s
- 1.任何一门编程语言均有相关数据类型。C#也不例外,其基本数据类型有int,short,long,float,double,string等。
- 首先来看看以下程序将会打印出什么:class Dog { public static void bark
- 在C/C++跨平台开发中,我们知道在Windows上可以通过VS,进行单步断点调试,这非常方便。但是我们如果编译好的动态库so,想要跟踪下其
- 一、一对一关联 1.1、提出需求根据班级id查询班级信息(带老师的信息)1.2、创建表和数据创建一张教师表和班级表,这里我们假设一
- 第一次下载好Android源代码工程后,我们通常是在Android源代码工程目
- 由于springboot常用war包部署,改为cloud开发模式多端口情况下,部署反而不习惯毕竟,war包要不要项目名访问都必须放在tomc
- 通过使用java mail来实现读取163邮箱,qq邮箱的邮件内容。1.代码实现创建springboot项目,引入依赖包<!--mai
- 一、饿汉式(静态常量)public class Face { private stat
- 本文实例讲述了C++语言实现线性表之链表实现方法。分享给大家供大家参考。具体分析如下:插入、删除结点的代码有点多,但这样提高了代码的可读性,
- 在Java项目开发中,Maven是非常重要的构建工具之一,它可以帮助我们管理项目的依赖、构建和发布。本文将通过以下两个方面来介绍Maven打
- 直接用javaw.exe想打开aspectj-1.9.4.jar安装aspectJ选Java™ Platform SE binary提示JV
- 在 C# WPF开发中颜色对话框控件(ColorDialog)用于对界面中的背景、文字…(拥有颜色属性的所有控件)设置