日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

C#序列化枚举为字符串和自定义转换器

發(fā)布時(shí)間:2024/8/1 C# 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#序列化枚举为字符串和自定义转换器 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

C#序列化枚舉為字符串和自定義轉(zhuǎn)換器

我所做的項(xiàng)目是需要調(diào)用業(yè)務(wù)算法的,算法中有一個(gè)入?yún)⑹怯推返男再|(zhì),這個(gè)性質(zhì)有名稱、編碼、類型等屬性,其中類型是固定質(zhì)量性質(zhì)、體積性質(zhì)和其他性質(zhì)這三種,所以我把其作為枚舉類型。問(wèn)題也由此產(chǎn)生,默認(rèn)情況下,枚舉是以其整數(shù)形式進(jìn)行 JSON 序列化,這就需要同研發(fā)算法的同事約定好數(shù)值的含義。但是經(jīng)過(guò)協(xié)商,算法同事要求我們傳遞成字符串。因此,我們希望它們?cè)谝恍┣闆r下以字符串的形式進(jìn)行序列化。本文將講解實(shí)現(xiàn)這一目標(biāo)的各種方法。

1、枚舉序列化的默認(rèn)行為

首先,我們有一個(gè)性質(zhì)類:

public class Property{public string Code { get; set; }public string Name { get; set; }public PropertyType ProType { get; set; }}public enum PropertyType{Volume,Weight,Other}

我們用 System.Text.Json 中的 Serialize 方法序列化一個(gè) Property 對(duì)象:

using System.Text.Json;var json = JsonSerializer.Serialize(new Property {Code = "DEN",Name = "密度",ProType = PropertyType.Volume });Console.WriteLine(json);

可以看到這個(gè)對(duì)象序列化為 Json 后的字符串:

{ "Code": "DEN", "Name": "密度", "ProType": 0}

正如我們所看到的,枚舉屬性的值(PropertyType.Volume)被序列化為 JSON 字符串后表現(xiàn)為一個(gè)整數(shù)(0)。

作為序列化結(jié)果 JSON 的消費(fèi)者,在沒(méi)有文檔的情況下,無(wú)法知道這個(gè)整數(shù)代表的業(yè)務(wù)含義。

所以,問(wèn)題來(lái)了。如何將枚舉屬性序列為更直觀的字符串形式呢?即,如何將上面示例中的對(duì)象序列化為:

{ "Code": "DEN", "Name": "密度", "ProType": "Volume" }

要把枚舉序列化為字符串,.Net 標(biāo)準(zhǔn)庫(kù) System.Text.Json 和 Newtonsoft 庫(kù)都為此提供了一個(gè)轉(zhuǎn)換器,分別為 JsonStringEnumConverter 和 StringEnumConverter。下面來(lái)看看它們的用法。

2、基于標(biāo)注的方式

.Net 標(biāo)準(zhǔn)庫(kù)和 Newtonsoft 庫(kù)都提供了一個(gè)轉(zhuǎn)換器特性 JsonConverterAttribute,我們可以用它來(lái)選擇性地標(biāo)注要序列化為字符串形式的枚舉屬性或類型。

標(biāo)注枚舉屬性

我們可以在枚舉屬性上使用 JsonConverterAttribute 特性來(lái)標(biāo)注 ProType 屬性,并使用 JsonStringEnumConverter 轉(zhuǎn)換器,如下:

using System.Text.Json.Serialization;public class Property{public string Code { get; set; }public string Name { get; set; }[JsonConverter(typeof(JsonStringEnumConverter))]public PropertyType ProType { get; set; }}

此時(shí)序列化的結(jié)果為:

{ "Code": "DEN", "Name": "密度", "ProType": "Volume" }

Newtonsoft 庫(kù)也是類似的,把 JsonStringEnumConverter 替換為 StringEnumConverter 即可。

標(biāo)注枚舉類型

JsonConverterAttribute 特性也可以應(yīng)用在自定義類型上面,把它應(yīng)用在 PropertyType 枚舉類型上:

using System.Text.Json.Serialization;[JsonConverter(typeof(JsonStringEnumConverter))] public enum PropertyType {Volume,Weight,Other }

這樣,所有的 PropertyType 枚舉都會(huì)序列化為字符串形式。

3、基于選項(xiàng)的方式

在一些不方便修改類或枚舉類型定義的情況下(如調(diào)用第三方 SDK),就不能使用標(biāo)注的方式將枚舉序列化為字符串了。.Net 標(biāo)準(zhǔn)庫(kù)和 Newtonsoft 庫(kù)還提供了帶有轉(zhuǎn)換選項(xiàng)參數(shù)的序列化方法,允許我們使用行內(nèi)(Inline)方式實(shí)現(xiàn)這一目標(biāo)。

.Net 標(biāo)準(zhǔn)庫(kù)示例如下:

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

而 Newtonsoft 庫(kù)稍有不同:

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

4、全局注冊(cè)的方式

基于特性標(biāo)注的方式讓我們可以靈活地以可控的方式來(lái)操作枚舉的序列化。而基于選項(xiàng)的方式允許我們?cè)谔囟ōh(huán)境下按需處理對(duì)象的序列化。但是,有沒(méi)有辦法讓所有的枚舉在默認(rèn)情況下被序列化為字符串呢?答案是有的。

對(duì)控制臺(tái)應(yīng)用程序或 .Net 類庫(kù)就簡(jiǎn)單了,直接封裝一個(gè)通用的序列化方法即可。這里我們主要關(guān)心如何在 ASP.NET Core 應(yīng)用程序中注冊(cè)全局的序列化規(guī)則。

在 ASP.NET Core Web API 應(yīng)用中,需要在 DI 管道中注冊(cè)枚舉轉(zhuǎn)換器,如下:

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 管道中注冊(cè)枚舉轉(zhuǎn)換器,但使用的是 Configure 方式:

var builder = WebApplication.CreateBuilder(args); builder.Services.Configure<JsonOptions>(options => {options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); });var app = builder.Build();app.MapGet("/", () => new Property {Code = "DEN",Name = "密度",ProType = PropertyType.Volume });app.Run();

如上所述,我們可以通過(guò)全局注冊(cè)的方式來(lái)設(shè)置應(yīng)用程序在默認(rèn)情況下將枚舉序列化為字符串,這樣可以保持類的干凈,也不需要在序列化時(shí)指定明確的選項(xiàng)。

5、標(biāo)志枚舉的序列化

標(biāo)志枚舉(bit-mask 枚舉)的默認(rèn)序列化輸出也是一個(gè)整數(shù),而不是使用標(biāo)志(Flag)的組合來(lái)表示。例如:

using System.Text.Json;var proTypes = PropertyType.Other | PropertyType.Weight; var json = JsonSerializer.Serialize(new { ProType = proTypes });Console.WriteLine(json);[Flags] public enum PropertyType {Volume = 0, Weight = 1, Other = 2 }

序列化結(jié)果為:

{ "ProType": 3 }

我們希望輸出的是枚舉的組合,結(jié)果卻是一個(gè)數(shù)字,這對(duì)消費(fèi)者來(lái)說(shuō)很難理解它真正的意義,我們希望它序列化為文件的組合。使用前面的枚舉字符串轉(zhuǎn)換器可以解決這個(gè)問(wèn)題,以基于選項(xiàng)的方式為例,示例代碼如下:

using System.Text.Json; using System.Text.Json.Serialization;var options = new JsonSerializerOptions(); options.Converters.Add(new JsonStringEnumConverter());var proTypes = PropertyType.Other | PropertyType.Weight; var json = JsonSerializer.Serialize(new { ProType = proTypes }, options);Console.WriteLine(json); { "ProType": "Other, Weight" }

這樣就得到我們想要的文本組合序列化結(jié)果了。

6、自定義枚舉字符串

在將枚舉序列化為字符串時(shí),我們可能希望進(jìn)行一些微調(diào)。例如,轉(zhuǎn)換為 camelCase 或其它更有意義的文本形式。

序列化為 camelCase 形式

JsonStringEnumConverter 有一個(gè)接收命名策略的重載構(gòu)造函數(shù),給其傳入 JsonNamingPolicy.CamelCase 參數(shù)即可將枚舉序列為 camelCase 文本形式,例如:

var options = new JsonSerializerOptions(); options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase)); var json = JsonSerializer.Serialize(new Property {Code = "DEN",Name = "密度",ProType = PropertyType.Volume });Console.WriteLine(json);

序列化結(jié)果為:

{ "Code": "DEN", "Name": "密度", "ProType": "volume" }
序列化為自定義文本

由于語(yǔ)言中的變量命名規(guī)則,枚舉成員在以常規(guī)方式序列化時(shí)并不總是能傳達(dá)有意義的文本。為了解決這個(gè)問(wèn)題,我們可以使用 EnumMemberAttribute 特性,它是專門為此目的引入的。我們來(lái)定義一個(gè)新的枚舉:

public enum PropertyType {[EnumMember(Value = "體積性質(zhì)")]volume,[EnumMember(Value = "質(zhì)量性質(zhì)")]Weight,[EnumMember(Value = "其他性質(zhì)")]Other, }

我們重新定義了一個(gè) PropertyType 枚舉,在其成員上標(biāo)注 EnumMember 特性,以提供更有意義的文本表達(dá)。

Newtonsoft 庫(kù)是支持的,序列化后,我們可以看到它輸出了我們想要的文本。

注:雖然 Donet 標(biāo)準(zhǔn)庫(kù)原生暫不支持將枚舉序列化為自定義的文本,但依然可以通過(guò)自定義轉(zhuǎn)換器來(lái)實(shí)現(xiàn)。

7、自定義轉(zhuǎn)換器

當(dāng)接收到的Json格式字符串與本地已有類型不統(tǒng)一時(shí),需要進(jìn)行自定義的反序列化過(guò)程,反之亦然,例如Json字符串中以字符串"TRUE"表示布爾類型true(不自定義,這個(gè)過(guò)程依然走的通,只是以此舉例),以字符串"FALSE"表示布爾類型false時(shí),需要自定義如下:

/// <summary> /// 自定義布爾類型數(shù)據(jù)轉(zhuǎn)換規(guī)則 /// </summary> public class MyBoolConverter : JsonConverter{private const string TrueStr = "TRUE";private const string FalseStr = "FALSE";public override bool CanConvert(Type objectType) => true;//反序列化 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {if (reader.ValueType == typeof(string)){if ((string)reader.Value == TrueStr){return true;}else {return false;}}return false;}//序列化 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {if (value.GetType() == typeof(bool)){bool result = (bool)value;if (result){writer.WriteValue(TrueStr);}else {writer.WriteValue(FalseStr);}}} }

然后,在需要操作的類型定義中的字段/屬性中加入該特性:

private class MyClass{[JsonConverter(typeof(MyBoolConverter))]public bool MyBool; }

此時(shí)

string jsonStr = @"{""MyBool"": ""TRUE""}"; MyClass1 myClass = JsonConvert.DeserializeObject<MyClass1>(jsonStr); Console.WriteLine(myClass.MyBool); //True Console.WriteLine(JsonConvert.SerializeObject(myClass)); //{"MyBool":"TRUE"}

8、總結(jié)

枚舉默認(rèn)是以其整數(shù)形式進(jìn)行 JSON 序列化的,這要求消費(fèi)者事先了解這些數(shù)字的實(shí)際含義,給代碼的理解也帶來(lái)了一定的困難。所以 .Net 基礎(chǔ)庫(kù)和流行的 Newtonsoft 庫(kù)都提供了將枚舉序列化為字符串的多種方法。根據(jù)需求,可以選擇使用本文講的基于特性標(biāo)注的方式、基于選項(xiàng)參數(shù)的方式和全局方式。

另外,除了可以將枚舉序列化為成員名字符串,還可以自定義文本的輸出,如輸出為 camelCase 文本形式和自定義輸出的文本內(nèi)容等。

總結(jié)

以上是生活随笔為你收集整理的C#序列化枚举为字符串和自定义转换器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。