.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.pswp.cn/news/284683.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284683.shtml
英文地址,請注明出處:http://en.pswp.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;…