当前位置: 首页 > article >正文

C#在Json序列化时将key和value转为对应的中文

在C#中,实体类可以通过System.Text.Json或Newtonsoft.Json库等方式直接序列化为json字符串,key为字段(属性)名,value为值。

上面的方式虽然实现简单,但是有个缺陷,就是转化后的json给外人展示时不够直观,key是英文的,有的value甚至是一些代号、枚举之类的,总之就是难以阅读和提取到有效的信息,不能应付老板的离谱需求。

下面介绍一种可行性的方案,在json序列化的时候,将key转为字段中文名,value转为对应的中文描述,通过继承重写Newtonsoft.Json库(演示版本为13.0.3)中的JsonConverter类来实现。

        1、写一个NameAttribute特性

FieldName:属性的中文名称,用于替换属性名(也就是原本的key);IsEnum:是否类枚举,用于处理int类型的代号。

/// <summary>
/// 属性中文名称的特性
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class NameAttribute : Attribute
{
    public string FieldName { get; }
    public bool IsEnum { get; }

    public NameAttribute(string fieldName)
    {
        FieldName = fieldName;
    }

    public NameAttribute(string fieldName, bool isEnum)
    {
        FieldName = fieldName;
        IsEnum = isEnum;
    }
}

        2、写一个KeyValue类,用来存原本value中的代号和对应的中文描述

/// <summary>
/// 键值模型
/// </summary>
public class KeyValue
{
    public KeyValue(int key, string value)
    {
        Key = key; 
        Value = value;
    }

    /// <summary>
    /// 键
    /// </summary>
    public int Key { get; set; }
    
    /// <summary>
    /// 值
    /// </summary>
    public string Value { get; set; }
}

        3、写一个泛型类JsonToChineseConverter<T>,继承JsonConverter

写一个有参构造函数,用来传递参数。这里传的是Dictionary类型,字典的key为实体类的属性名称;字典的value为List<KeyValue>类型,用来存类枚举。

/// <summary>
/// 传入value为list类型的中文名称
/// </summary>
private Dictionary<string, List<KeyValue>> KvDic { get; set; } = new Dictionary<string, List<KeyValue>>();
public JsonToChineseConverter(Dictionary<string, List<KeyValue>> kvDic)
{
    KvDic = kvDic;
}

继承JsonConverter的类需要重写一下3个方法:

        a、重写CanConvert方法,用来校验类型

/// <summary>
/// 校验能够转化的类型
/// </summary>
/// <param name="objectType"></param>
/// <returns></returns>
public override bool CanConvert(Type objectType)
{
    return objectType == typeof(T);
}

        b、重写ReadJson方法,用来读取json字符串,反序列化的时候使用,这里不做实现

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    throw new NotImplementedException("Deserialize is not implemented.");
}

        c、重写WriteJson方法,用来读取实体类字段和值,序列化的时候使用

通过反射的方式取实体类的字段、值和Name特性;忽略value为null、空的字符串、DateTime.MinValue、DateTime.MaxValue的字段,可自行调整。

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    JObject jsonObject = new JObject();
    PropertyInfo[] properties = value.GetType().GetProperties();

    foreach (PropertyInfo property in properties)
    {
        //value为null、空的字符串、DateTime.MinValue、DateTime.MaxValue时,则忽略
        object fieldValue = property.GetValue(value);
        if (fieldValue == null || string.IsNullOrWhiteSpace(fieldValue.ToString()) || (property.PropertyType == typeof(DateTime) && (Convert.ToDateTime(fieldValue) == DateTime.MinValue || Convert.ToDateTime(fieldValue) == DateTime.MaxValue)))
        {
            continue;
        }

        //key默认字段名,有Name注解时则取中文名
        string fieldName = property.Name;

        //取Name注解
        NameAttribute nameAttribute = property.GetCustomAttribute<NameAttribute>();
        if (nameAttribute != null)
        {
            fieldName = nameAttribute.FieldName;
        }

        //需校验字典中key是否存在,不然会报错
        bool keyExist = KvDic.ContainsKey(property.Name);

        //字段为List<int>类型时,将int转为对应的对应的中文
        if (property.PropertyType == typeof(List<int>) && keyExist)
        {
            var kv = KvDic[property.Name];
            if (kv != null && kv.Count > 0)
            {
                var fv = fieldValue as List<int>;
                fieldValue = kv.Where(d => fv.Contains(d.Key)).Select(d => d.Value).ToList();
            }
        }
        else if (property.PropertyType == typeof(int) && nameAttribute != null && nameAttribute.IsEnum == true && keyExist)
        {
            var kv = KvDic[property.Name];
            if (kv != null && kv.Count > 0)
            {
                var fv = fieldValue as int?;
                fieldValue = (kv.FirstOrDefault(d => d.Key == fv.Value)?.Value) ?? fieldValue;
            }
        }
        else if (property.PropertyType == typeof(bool))
        {
            if (Convert.ToBoolean(fieldValue) == true)
            {
                fieldValue = "是";
            }
            else
            {
                fieldValue = "否";
            }
        }

        jsonObject[fieldName] = JToken.FromObject(fieldValue, serializer);
    }

    jsonObject.WriteTo(writer);
}

完整的类代码如下:

/// <summary>
/// 用Newtonsoft.Json序列化JSON时的扩展,将key、value转为对应的中文名称
/// </summary>
/// <typeparam name="T"></typeparam>
public class JsonToChineseConverter<T> : JsonConverter
{
    /// <summary>
    /// 传入value为list类型的中文名称
    /// </summary>
    private Dictionary<string, List<KeyValue>> KvDic { get; set; } = new Dictionary<string, List<KeyValue>>();
    public JsonToChineseConverter(Dictionary<string, List<KeyValue>> kvDic)
    {
        KvDic = kvDic;
    }

    /// <summary>
    /// 校验能够转化的类型
    /// </summary>
    /// <param name="objectType"></param>
    /// <returns></returns>
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(T);
    }

    /// <summary>
    /// 读取JSON,不实现
    /// </summary>
    /// <param name="reader"></param>
    /// <param name="objectType"></param>
    /// <param name="existingValue"></param>
    /// <param name="serializer"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("Deserialize is not implemented.");
    }

    /// <summary>
    /// 写入JSON
    /// </summary>
    /// <param name="writer"></param>
    /// <param name="value"></param>
    /// <param name="serializer"></param>
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        JObject jsonObject = new JObject();
        PropertyInfo[] properties = value.GetType().GetProperties();

        foreach (PropertyInfo property in properties)
        {
            //value为null、空的字符串、DateTime.MinValue、DateTime.MaxValue时,则忽略
            object fieldValue = property.GetValue(value);
            if (fieldValue == null || string.IsNullOrWhiteSpace(fieldValue.ToString()) || (property.PropertyType == typeof(DateTime) && (Convert.ToDateTime(fieldValue) == DateTime.MinValue || Convert.ToDateTime(fieldValue) == DateTime.MaxValue)))
            {
                continue;
            }

            //key默认字段名,有Name注解时则取中文名
            string fieldName = property.Name;

            //取Name注解
            NameAttribute nameAttribute = property.GetCustomAttribute<NameAttribute>();
            if (nameAttribute != null)
            {
                fieldName = nameAttribute.FieldName;
            }

            //需校验字典中key是否存在,不然会报错
            bool keyExist = KvDic.ContainsKey(property.Name);

            //字段为List<int>类型时,将int转为对应的对应的中文
            if (property.PropertyType == typeof(List<int>) && keyExist)
            {
                var kv = KvDic[property.Name];
                if (kv != null && kv.Count > 0)
                {
                    var fv = fieldValue as List<int>;
                    fieldValue = kv.Where(d => fv.Contains(d.Key)).Select(d => d.Value).ToList();
                }
            }
            else if (property.PropertyType == typeof(int) && nameAttribute != null && nameAttribute.IsEnum == true && keyExist)
            {
                var kv = KvDic[property.Name];
                if (kv != null && kv.Count > 0)
                {
                    var fv = fieldValue as int?;
                    fieldValue = (kv.FirstOrDefault(d => d.Key == fv.Value)?.Value) ?? fieldValue;
                }
            }
            else if (property.PropertyType == typeof(bool))
            {
                if (Convert.ToBoolean(fieldValue) == true)
                {
                    fieldValue = "是";
                }
                else
                {
                    fieldValue = "否";
                }
            }

            jsonObject[fieldName] = JToken.FromObject(fieldValue, serializer);
        }

        jsonObject.WriteTo(writer);
    }
}

        4、单元测试

下面用TestModel类进行测试

public class TestModel()
{
    [Name("ID")]
    public int Id { get; set; }

    [Name("姓名")]
    public string Name { get; set; }

    [Name("性别", true)]
    public int Sex { get; set; }

    [Name("年龄")]
    public int Arg { get; set; }

    [Name("老师")]
    public List<int> Teacher { get; set; }

    [Name("是否毕业")]
    public bool IsGraduation { get; set; }

    public int? Field1 { get; set; } = null;
    public string Field2 { get; set; } = "  ";
    public DateTime Field3 { get; set; } = DateTime.MinValue;
    public DateTime Field4 { get; set; } = DateTime.MaxValue;
    public bool Field5 { get; set; } = false;
}

测试方法如下:

[TestMethod]
public void WriteJsonTest1()
{
    TestModel model = new TestModel()
    {
        Id = 1,
        Name = "张楚岚",
        Sex = 1,
        Arg = 22,
        Teacher = new List<int>() { 1, 2 },
        IsGraduation = true
    };

    Dictionary<string, List<KeyValue>> kvDic = new Dictionary<string, List<KeyValue>>();
    kvDic.Add("Sex", new List<KeyValue>() { new KeyValue(0, "未知"), new KeyValue(1, "男"), new KeyValue(2, "女") });
    kvDic.Add("Teacher", new List<KeyValue>() { new KeyValue(1, "张怀义"), new KeyValue(2, "张之维") });

    string joStr = JsonConvert.SerializeObject(model, new JsonSerializerSettings
    {
        Converters = new List<JsonConverter>() { new JsonToChineseConverter<TestModel>(kvDic) },
    });
}

输出结果:


http://www.kler.cn/a/507271.html

相关文章:

  • SpringSecurity-前后端分离
  • 港科夜闻 | 香港科大与微软亚洲研究院签署战略合作备忘录,推动医学健康教育及科研协作...
  • 微软开源AI Agent AutoGen 详解
  • 类模板的使用方法
  • Nginx 如何设置 Upgrade-Insecure-Requests 报头 ?
  • Multi-Agent如何设计
  • jmeter事务控制器-勾选Generate Parent Sample
  • 基于单片机的智能计步器电路设计
  • Flink Standalone 方案中解决挂机问题
  • 树莓派5--系统问题汇总
  • Qt 线程常用通信方式
  • 【LeetCode】每日一题 2024_1_14 超过阈值的最少操作数 I(简单模拟)
  • 安全测评主要标准
  • java实现树形递归
  • flutter在使用gradle时的加速
  • python中数据可视化库(Matplotlib)
  • PCL 获取指定区域的点【2025最新版】
  • 万字长文介绍ARINC 653,以及在综合模块化航空电子设备(IMA)中的作用
  • 如何使用Ultralytics训练自己的yolo5 yolo8 yolo10 yolo11等目标检测模型
  • 强化学习-蒙特卡洛方法
  • 数据库基础实验1(创建表,设置外键,检查,不为空,主键等约束)安装mysql详细步骤
  • 通过智能合约攻击漏洞:夺取合约所有权并提取余额
  • 立创开发板入门第六课 音频-扬声器和麦克风 I2S驱动
  • 3 前端(上): Web开发相关概念 、HTML语法、CSS语法
  • 【Golang 面试题】每日 3 题(三十)
  • MiniCPM-o 2.6:开源大型语言模型在多模态任务上超越GPT-4o和Claude 3.5