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

news2025/1/20 1:18:35

在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.coloradmin.cn/o/2279136.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

23- TIME-LLM: TIME SERIES FORECASTING BY REPRO- GRAMMING LARGE LANGUAGE MODELS

解决问题 用LLM来解决时序预测问题&#xff0c;并且能够将时序数据映射&#xff08;reprogramming&#xff09;为NLP token&#xff0c;并且保持backbone的大模型是不变的。解决了时序序列数据用于大模型训练数据稀疏性的问题。 方法 Input Embedding 输入&#xff1a; X …

使用 Java 开发 Android 应用:Kotlin 与 Java 的混合编程

使用 Java 开发 Android 应用&#xff1a;Kotlin 与 Java 的混合编程 在开发 Android 应用程序时&#xff0c;我们通常可以选择使用 Java 或 Kotlin 作为主要的编程语言。然而&#xff0c;有些开发者可能会想要在同一个项目中同时使用这两种语言&#xff0c;这就是所谓的混合编…

左神算法基础提升--4

文章目录 树形dp问题Morris遍历 树形dp问题 求解这个问题需要用到我们在基础班上学到的从节点的左子树和右子树上拿信息的方法。 求最大距离主要分为两种情况&#xff1a;1.当前节点参与最大距离的求解&#xff1b;2.当前节点不参与最大距离的求解&#xff1b; 1.当前节点参与最…

拆分工作簿转换PDF格式文件一步到位-Excel易用宝

今天一大早老板急匆匆的跑进办公室说&#xff0c;快快快&#xff0c;&#xff0c;快把这个工作簿中的工作表拆分出来&#xff0c;然后转换成PDF格式文件发给客户。 我一看这么多工作表&#xff0c;又是拆分表格&#xff0c;又是转换文件&#xff0c;这么复杂的工作&#xff0c…

SSM课设-学生管理系统

【课设者】SSM课设-学生管理系统 技术栈: 后端: SpringSpringMVCMybatisMySQLJSP 前端: HtmlCssJavaScriptEasyUIAjax 功能: 学生端: 登陆 学生信息管理 个人信息管理 老师端: 多了教师信息管理 管理员端: 多了班级信息管理 多了年级信息管理 多了系统用户管理

Python调用go语言编译的库

要在 Python 中调用用 Go 语言编写的库&#xff0c;可以使用 Go 语言的 cgo 特性将 Go 代码编译成共享库&#xff08;如 .so 文件&#xff09;&#xff0c;然后在 Python 中通过 ctypes 或 cffi 模块加载和调用这个共享库。 新建main.go文件&#xff0c;使用go语言编写如下代码…

JavaWeb简单开发

JavaWeb 开发是指基于 Java 技术栈进行 Web 应用开发的过程&#xff0c;主要依赖于 Java EE 或者 Spring 框架来构建服务器端应用。JavaWeb 的技术栈比较广泛&#xff0c;通常包括以下几个部分&#xff1a; 示例&#xff1a;简单的 JavaWeb 应用&#xff08;Spring Boot Thyme…

[Mac + Icarus Verilog + gtkwave] Mac运行Verilog及查看波形图

目录 1. MAC安装环境 1. 1 Icarus Verilog 编译 1. 2 gtkwave 查看波形 2. 安装遇到的问题 2. 1 macOS cannot verify that this app is free from malware 2. 2 gtkwave-bin is not compatible with macOS 14 or later 3. 运行示例 3. 1 源代码 3. 2 编译Verilog 3. 3 生成.v…

Phi小模型开发教程:用C#开发本地部署AI聊天工具,只需CPU,不需要GPU,3G内存就可以运行,不输GPT-3.5

大家好&#xff0c;我是编程乐趣。 行业诸多大佬一直在说&#xff1a;“‌2025年将是AI应用元年‌”&#xff0c;虽然说大佬的说法不一定对&#xff0c;但AI趋势肯定没错的。 对于我们程序员来说&#xff0c;储备AI应用开发技能&#xff0c;不管对找工作、接项目、创业肯定是…

物联网网关Web服务器--Boa服务器移植与测试

1、Boa服务器介绍 BOA 服务器是一个小巧高效的web服务器&#xff0c;是一个运行于unix或linux下的&#xff0c;支持CGI的、适合于嵌入式系统的单任务的http服务器&#xff0c;源代码开放、性能高。 Boa 嵌入式 web 服务器的官方网站是http://www.boa.org/。 特点 轻量级&#x…

Maven的多模块架构设计诺依的多模块

Maven的多模块架构设计 多模块架构设计&#xff0c;本文采用 诺依的多模块架构设计分析

.Net 6.0 .Net7.0 .Net8.0 .Net9.0 使用 Serilog 按日志等级写入日志及 appsetting.json 配置方式实现

前言 最近使用最新版的Serilog记录日志时&#xff0c;发现以前有些关于Serilog的Nuget弃用了&#xff0c;最关键的是有些配置写法也改变&#xff0c;于是就整理了一下最新版的Serilog配置方式(appsetting.json)的使用 说明&#xff1a;我是用的.Net6&#xff0c;最新长期支持…

数字化时代,传统代理模式的变革之路

在数字化飞速发展的今天&#xff0c;线上线下融合&#xff08;O2O&#xff09;成了商业领域的大趋势。这股潮流&#xff0c;正猛烈冲击着传统代理模式&#xff0c;给它带来了新的改变。 咱们先看看线上线下融合现在啥情况。线上渠道那是越来越多&#xff0c;企业纷纷在电商平台…

wireshark上没有显示出来rtp协议如何处理

分析》启用的协议 搜索rtp&#xff0c;勾选上rtp_udp即可。

edge浏览器恢复旧版滚动条

1、地址栏输入edge://flags 2、搜索Fluent scrollbars.&#xff0c;选择disabled&#xff0c;重启即可

使用 Java 和 FreeMarker 实现自动生成供货清单,动态生成 Word 文档,简化文档处理流程。

在上一篇博客中主要是使用SpringBootApache POI实现了BOM物料清单Excel表格导出&#xff0c;详见以下博客&#xff1a; Spring Boot Apache POI 实现 Exc&#xff08;&#xff09;el 导出&#xff1a;BOM物料清单生成器&#xff08;支持中文文件名、样式美化、数据合并&#…

二进制/源码编译安装mysql 8.0

二进制方式&#xff1a; 1.下载或上传安装包至设备&#xff1a; 2.创建组与用户&#xff1a; [rootopenEuler-1 ~]# groupadd mysql [rootopenEuler-1 ~]# useradd -r -g mysql -s /bin/false mysql 3.解压安装包&#xff1a; tar xf mysql-8.0.36-linux-glibc2.12-x86_64.ta…

VB.net实战(VSTO):解决WPS Ribbon图标灰色背景

问题&#xff1a;用VSTO制作插件&#xff0c;在MS Office中图标显示正常&#xff0c;但在WPS Office中图标显示为灰色背景 原因&#xff1a;使用的图标是纯透明背景的&#xff0c;这样的图标在WPS中会变为灰色背景。 以下这个解决办法是我自己摸索出来的&#xff0c;对您有用的…

搭建一个基于Spring Boot的书籍学习平台

搭建一个基于Spring Boot的书籍学习平台可以涵盖多个功能模块&#xff0c;例如用户管理、书籍管理、学习进度跟踪、笔记管理、评论和评分等。以下是一个简化的步骤指南&#xff0c;帮助你快速搭建一个基础的书籍学习平台。 — 1. 项目初始化 使用 Spring Initializr 生成一个…

金融项目实战 06|Python实现接口自动化——日志、实名认证和开户接口

目录 一、日志封装及应用&#xff08;理解&#xff09; 二、认证开户接口脚本编写 1、代码编写 1️⃣api目录 2️⃣script目录 2、BeautifulSoup库 1️⃣简介及例子 2️⃣提取html数据工具封装 3、认证开户参数化 一、日志封装及应用&#xff08;理解&#xff09; &…