.NET 序列化枚举为字符串

默认情况下,枚举是以其整数形式进行 JSON 序列化,这通常会导致与消费者应用缺乏互操作性,因为他们需要事先了解这些数字的实际含义。因此,我们希望它们在一些情况下以字符串的形式进行序列化。本文将讲解实现这一目标的各种方法。

1枚举序列化的默认行为

为了演示,我们来创建一个简单的 Model:

public class Circle
{public double Radius { get; set; }public Color BgColor { get; set; }
}public enum Color
{White, LightGray, Black
}

我们用 System.Text.Json 中的 Serialize 方法序列化一个 Circle 对象:

using System.Text.Json;var json = JsonSerializer.Serialize(new Circle
{Radius = 10.1,BgColor = Color.Black
});Console.WriteLine(json);

我们来看一下这个 Model 序列化为 Json 后的字符串:

{ "Radius": 10.1, "BgColor": 2 }

正如你看到的,枚举属性的值(Color.Black)被序列化为 JSON 字符串后表现为一个整数(2)。

作为序列化结果 JSON 的消费者,在没有文档的情况下,无法知道这个整数代表的业务含义。

所以,问题来了。如何将枚举属性序列为更直观的字符串形式呢?即,如何将上面示例中的对象序列化为:

{ "Radius": 10.1, "BgColor": "Black" }

要把枚举序列化为字符串,Dotnet 标准库 System.Text.Json 和 Newtonsoft 库都为此提供了一个转换器,分别为 JsonStringEnumConverterStringEnumConverter。下面来看看它们的用法。

2基于标注的方式

Dotnet 标准库和 Newtonsoft 库都提供了一个转换器特性 JsonConverterAttribute,我们可以用它来选择性地标注要序列化为字符串形式的枚举属性或类型。

标注枚举属性

我们可以在枚举属性上使用 JsonConverterAttribute 特性来标注 BgColor 属性,并使用 JsonStringEnumConverter 转换器,如下:

using System.Text.Json.Serialization;public class Circle
{public double Radius { get; set; }[JsonConverter(typeof(JsonStringEnumConverter))]public Color BgColor { get; set; }
}

此时序列化的结果为:

{ "Radius": 10.1, "BgColor": "Black" }

Newtonsoft 库也是类似的,把 JsonStringEnumConverter 替换为 StringEnumConverter 即可,本文就不重复举列了。

标注枚举类型

JsonConverterAttribute 特性也可以应用在自定义类型上面,把它应用在 Color 枚举类型上:

using System.Text.Json.Serialization;[JsonConverter(typeof(JsonStringEnumConverter))]
public enum Color
{White, LightGray, Black
}

这样,所有的 Color 枚举都会序列化为字符串形式。

3基于选项的方式

在一些不方便修改 Model 或枚举类型定义的情况下(如调用第三方 SDK),就不能使用标注的方式将枚举序列化为字符串了。Dotnet 标准库和 Newtonsoft 库还提供了带有转换选项参数的序列化方法,允许我们使用行内(Inline)方式实现这一目标。

Dotnet 标准库示例如下:

public static string SerializeWithStringEnum(object obj)
{var options = new JsonSerializerOptions();options.Converters.Add(new JsonStringEnumConverter());return JsonSerializer.Serialize(obj, options);
}

而 Newtonsoft 库稍有不同:

public static string SerializeWithStringEnum(object obj)
{var converter = new StringEnumConverter();return JsonConvert.SerializeObject(obj, converter);
}

4全局注册的方式

基于特性标注的方式让我们可以灵活地以可控的方式来操作枚举的序列化。而基于选项的方式允许我们在特定环境下按需处理对象的序列化。但是,有没有办法让所有的枚举在默认情况下被序列化为字符串呢?答案是有的。

对控制台应用程序或 Dotnet 类库就简单了,直接封装一个通用的序列化方法即可。这里我们主要关心如何在 ASP.NET Core 应用程序中注册全局的序列化规则。

在 ASP.NET Core Web API 应用中,需要在 DI 管道中注册枚举转换器,如下:

var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllers().AddJsonOptions(options =>{options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());});var app = builder.Build();app.MapControllers();app.Run();

在 ASP.NET Core Minimal API 中,也是需要在 DI 管道中注册枚举转换器,但使用的是 Configure 方式:

var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<JsonOptions>(options =>
{options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
});var app = builder.Build();app.MapGet("/", () => new Circle
{Radius = 10.1,BgColor = Color.Black
});app.Run();

如上所述,我们可以通过全局注册的方式来设置应用程序在默认情况下将枚举序列化为字符串,这样可以保持 Model 的干净,也不需要在序列化时指定明确的选项。

5标志枚举的序列化

标志枚举(bit-mask 枚举)的默认序列化输出也是一个整数,而不是使用标志(Flag)的组合来表示。例如:

using System.Text.Json;var colors = Color.LightGray | Color.Black;
var json = JsonSerializer.Serialize(new { Colors = colors });Console.WriteLine(json);[Flags]
public enum Color
{White = 0, LightGray = 1, Black = 2
}

序列化结果为:

{ "Colors": 3 }

我们希望输出的是枚举的组合,结果却是一个数字,这对消费者来说很难理解它真正的意义,我们希望它序列化为文件的组合。使用前面的枚举字符串转换器可以解决这个问题,以基于选项的方式为例,示例代码如下:

using System.Text.Json;
using System.Text.Json.Serialization;var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());var colors = Color.LightGray | Color.Black;
var json = JsonSerializer.Serialize(new { Colors = colors }, options);Console.WriteLine(json);
{ "Colors": "LightGray, Black" }

这样就得到我们想要的文本组合序列化结果了。

6自定义枚举字符串

在将枚举序列化为字符串时,我们可能希望进行一些微调。例如,转换为 camelCase 或其它更有意义的文本形式。

序列化为 camelCase 形式

JsonStringEnumConverter 有一个接收命名策略的重载构造函数,给其传入 JsonNamingPolicy.CamelCase 参数即可将枚举序列为 camelCase 文本形式,例如:

var options = new JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
var json = JsonSerializer.Serialize(new Circle
{Radius = 10.1,BgColor = Color.LightGray
});Console.WriteLine(json);

序列化结果为:

{ "Radius": 10.1, "BgColor": "lightGray" }

序列化为自定义文本

由于语言中的变量命名规则,枚举成员在以常规方式序列化时并不总是能传达有意义的文本。为了解决这个问题,我们可以使用 EnumMemberAttribute 特性,它是专门为此目的引入的。我们来定义一个新的枚举:

public enum ColorScheme
{[EnumMember(Value = "白/蓝")]WhiteBlue,[EnumMember(Value = "红/黑")]RedBlack,
}

我们定义了一个 ColorScheme 枚举,在其成员上标注 EnumMember 特性,以提供更有意义的文本表达。

遗憾的,Donet 标准库 System.Text.Json 原生暂不支持这种自定义文本的序列化。但 Newtonsoft 库是支持的,示例代码如下:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization;var converter = new StringEnumConverter();
var json = JsonConvert.SerializeObject(new TShirt
{Name = "男士衬衫-休闲款",ColorScheme = ColorScheme.WhiteBlue
}, converter);Console.WriteLine(json);public class TShirt
{public string? Name { get; set; }public ColorScheme ColorScheme { get; set; }
}

序列化后输出结果:

{ "Name": "男士衬衫-休闲款", "ColorScheme": "白/蓝" }

序列化后,我们可以看到它输出了我们想要的文本。

注:虽然 Donet 标准库原生暂不支持将枚举序列化为自定义的文本,但依然可以通过自定义转换器来实现。

7总结

枚举默认是以其整数形式进行 JSON 序列化的,这要求消费者事先了解这些数字的实际含义,给代码的理解也带来了一定的困难。所以 Dotnet 基础库和流行的 Newtonsoft 库都提供了将枚举序列化为字符串的多种方法。根据需求,可以选择使用本文讲的基于特性标注的方式、基于选项参数的方式和全局方式。

另外,除了可以将枚举序列化为成员名字符串,还可以自定义文本的输出,如输出为 camelCase 文本形式和自定义输出的文本内容等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284683.shtml

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

相关文章

ArcGIS实验教程——实验四十四:ArcGIS地图浮雕效果制作完整案例教程

ArcGIS制作地图时可以制作出很多很炫的效果,比如地图阴影、地图晕渲效果、浮雕效果、三维效果等等。本实验讲解在ArcGIS中制作浮雕效果地图,效果如下所示: 扩展阅读:【ArcGIS Pro微课1000例】0016:ArcGIS Pro 2.8浮雕效果地图制图案例教程 1. 加载矢量数据 加载实验数据包…

Mysql,SqlServer,Oracle主键自动增长的设置

参考文献 http://blog.csdn.net/andyelvis/article/details/2446865 1、把主键定义为自动增长标识符类型 MySql 在mysql中&#xff0c;如果把表的主键设为auto_increment类型&#xff0c;数据库就会自动为主键赋值。例如&#xff1a; create table customers(id int auto_incre…

Chapter 3 Phenomenon——19

His unfriendliness intimidated me. 他的不友好恐吓到了我。 My words came out with less severity than Id intended. 我说出来的言辞比我打算的要不严厉一些。 我说出的话远远没有达到我所想要的充满火药味的效果。 "You owe me an explanation," I reminded him…

Javascript 面向对象编程(一):封装

Javascript是一种基于对象&#xff08;object-based&#xff09;的语言&#xff0c;你遇到的所有东西几乎都是对象。但是&#xff0c;它又不是一种真正的面向对象编程&#xff08;OOP&#xff09;语言&#xff0c;因为它的语法中没有class&#xff08;类&#xff09;。 那么&am…

【ArcGIS Pro微课1000例】0016:ArcGIS Pro 2.8浮雕效果地图制图案例教程

ArcGIS Pro制作地图时可以制作出很多很炫的效果,比如地图阴影、地图晕渲效果、浮雕效果、三维效果等等。本实验讲解在ArcGIS Pro 2.8中制作浮雕效果地图,效果如下所示: 【参考阅读】:ArcGIS实验教程——实验四十四:ArcGIS地图浮雕效果制作完整案例教程 1. 加载矢量数据 …

用正则实现多行文本合并,从而保存为csv文件

有如下文本&#xff0c;想实现每三行合并为一行&#xff0c;最终生成csv文件 分数 人数 累计人数 661及以上 23 23 660 3 26 659 5 31 658 5 36 657 9 45 656 10 55 655 4 59 654 6 65 653 15 80查找项&#xff1a; ^(.) ^(.) ^(.)替换项&#xff1a; $1,$2,$3替换结果&…

聊一聊 C# 后台GC 到底是怎么回事?

一&#xff1a;背景 写这一篇的目的主要是因为.NET领域内几本关于阐述GC方面的书&#xff0c;都是纯理论&#xff0c;所以懂得人自然懂&#xff0c;不懂得人也没法亲自验证&#xff0c;这一篇我就用 windbg 源码 让大家眼见为实。二&#xff1a;为什么要引入后台GC 1. 后台GC到…

【BIM入门实战】Revit中的墙体层次以及常见问题解答

一、Revit墙体的层次 1. Revit墙体的层次如图 Revit绘制墙体时,要先选择定位线,可以选核心层中心线,也可以选墙中心线,当墙体为对称时,核心层中心线与墙中心线会重合。 2. 具体层次 1)结构[1]:必须在核心边界内 2)衬底[2]:其他材质基础的材料,如胶合板或石膏板 3…

Spring Boot 使用Redis

转载自&#xff1a;http://www.cnblogs.com/ityouknow/p/5748830.html Redis支持更丰富的数据结构&#xff0c;例如hashes, lists, sets等&#xff0c;同时支持数据持久化。除此之外&#xff0c;Redis还提供一些类数据库的特性&#xff0c;比如事务&#xff0c;HA&#xff0c;主…

工具链接

OmniGraffle Pro 7.0.2 Mac中文破解版 | 史蒂芬周的博客        http://www.sdifenzhou.com/omnigrafflepro702.html 转载于:https://www.cnblogs.com/wfwenchao/p/6393097.html

FlashCache初体验

FlashCache初体验 注意&#xff1a; 测试用的是CentOS6.5 内核版本2.6.32-431.el6.x86_64 步骤&#xff1a; 上传CentOS6.5做本地yum源&#xff0c;安装以下包。 yum install gcc yum install *kernel* yum install perl 将flashcache master打包下载至测试机上&#xff0c;可以…

用python将指定目录下的所有json文件合并成一个csv文件

#!/usr/bin/env python # -*- encoding: utf-8 -*-import sys import json import os import pandas as pd import csv""" 获取文件名列表 """ def list_file_names(folder):exist_files os.listdir(folder)file_list []for f in exist_files:…

【系统设计】分布式键值数据库

键值存储 ( key-value store )&#xff0c;也称为 K/V 存储或键值数据库&#xff0c;这是一种非关系型数据库。每个值都有一个唯一的 key 关联&#xff0c;也就是我们常说的 键值对。常见的键值存储有 Redis, Amazon DynamoDB&#xff0c;Microsoft Azure Cosmos DB&#xff0c…

keras系列︱Application中五款已训练模型、VGG16框架(Sequential式、Model式)解读(二)...

引自&#xff1a;http://blog.csdn.net/sinat_26917383/article/details/72859145 中文文档&#xff1a;http://keras-cn.readthedocs.io/en/latest/ 官方文档&#xff1a;https://keras.io/ 文档主要是以keras2.0。 . . Keras系列&#xff1a; 1、keras系列︱Sequential与Mo…

【BIM入门实战】Revit建筑墙体:构造、包络、叠层图文详解

本文主要讲解Revit建筑墙体:构造、包络、叠层。 一、基本墙 第一步: 选择菜单栏的【建筑】选项卡中的【墙】下拉菜单→【属性】面板中切换至基本墙→点击属性面板中的【编辑类型】,弹出如下墙体对话框。 第二步: 选择【复制】按钮→重新进行编辑名称,命名为“外墙-1F-2…

win11 恢复win10开始菜单及任务栏

Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced] "Start_ShowClassicMode"dword:00000001 "TaskbarSi"dword:00000000将上述代码存为reg文件&#xff0c;双击导入注册表。 任务栏…

CentOS安装Tomcat

1. 下载Tomcat安装包&#xff1a; Tomcat官网 解压下载下来的tar.gz至任意目录下&#xff0c;执行命令&#xff1a; Java代码 tar -xzf apache-tomcat-7.0.56.tar.gz 解压后如图&#xff1a; 如果是在windows上&#xff0c;则直接解压zip包到任意目录&…

【BIM+GIS】ArcGIS Pro2.8如何打开Revit模型,BIM和GIS融合?

ArcGIS Pro2.8中,可以直接打开Revit模型(.rvt)项目文件,实现了从数据格式方面BIM与GIS的有机融合,具体操作如下所示: 1. Revit2018模型绘制 打开Revit2018软件,选择【建筑样板】,打开标高1楼层平面,新建一个简单的户型:包括四面墙体、2个门和一扇窗户,如下图所示。…

Edge 开发者沙龙|一小时精通Edge扩展开发

点击蓝字关注我们编辑&#xff1a;Alan Wang排版&#xff1a;Rani Sun微软 Reactor 为帮助广开发者&#xff0c;技术爱好者&#xff0c;更好的学习 .NET Core, C#, Python&#xff0c;数据科学&#xff0c;机器学习&#xff0c;AI&#xff0c;区块链, IoT 等技术&#xff0c;将…

tomcat 开启远程debug

1、linux服务器上tomcat配置startup.sh 文件末尾添加&#xff08;不换行&#xff09;&#xff1a;declare -x CATALINA_OPTS"-server -Xdebug -Xnoagent -Djava.compilerNONE -Xrunjdwp:transportdt_socket,servery,suspendn,address9876"2、eclipse配置&#xff1a;…