【C# 序列化】 自定义Json转换器模式
【C# 序列化】 自定义Json转换器
Json转换器简介
本文介绍如何为 System.Text.Json 命名空间中提供的 JSON 序列化类创建自定义转换器。
转换器是一种将对象或值与 JSON 相互转换的类。 System.Text.Json
命名空间为映射到 JavaScript 基元的大多数基元类型提供内置转换器。 可以编写自定义转换器来实现以下目标:
- 重写内置转换器的默认行为。 例如,你可能希望通过 mm/dd/yyyy 格式来表示
DateTime
值。 默认情况下,支持 ISO 8601-1:2019,包括 RFC 3339 配置文件。 有关详细信息,请参阅 中的 DateTime 和 DateTimeOffset 支持。 - 支持自定义值类型。 例如,
PhoneNumber
结构。
还可以编写自定义转换器,以使用当前版本中未包含的功能自定义或扩展 System.Text.Json
。 本文后面部分介绍了以下方案:
自定义转换器模式(基本模式和工厂模式)
用于创建自定义转换器的模式有两种:基本模式和工厂模式。 工厂模式适用于处理类型 Enum
或开放式泛型的转换器。 基本模式适用于非泛型或封闭式泛型类型。 例如,适用于以下类型的转换器需要工厂模式:
可以通过基本模式处理的类型的一些示例包括:
基本模式创建的类可以处理一种类型。 工厂模式创建的类在运行时确定所需的特定类型,并动态创建适当的转换器。
自定义基本模式转换器
遵循基本模式的步骤
以下步骤说明如何遵循基本模式来创建转换器:
- 创建一个派生自 JsonConverter<T> 的类,其中
T
是要进行序列化和反序列化的类型。 - 重写
Read
方法,以反序列化传入 JSON 并将其转换为类型T
。 使用传递给方法的 Utf8JsonReader 读取 JSON。 无需担心处理部分数据,因为序列化程序会传递当前 JSON 范围的所有数据。 因此,不需要调用 Skip 或 TrySkip,也不需要验证 Read 是否返回true
。 - 重写
Write
方法以序列化T
类型的传入对象。 使用传递给方法的 Utf8JsonWriter 写入 JSON。 - 仅当需要时才重写
CanConvert
方法。 当要转换的类型属于类型T
时,默认实现会返回true
。 因此,仅支持类型T
的转换器不需要重写此方法。 有关的确需要重写此方法的转换器的示例,请参阅本文后面的多态反序列化部分。
可以参阅内置转换器源代码作为用于编写自定义转换器的参考实现。
属性上的 [JsonConverter]
- 将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。
- 将 [JsonConverter] 特性应用于需要自定义转换器的属性
JsonSerializerOptions op = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, Converters = { new MYEnumToUpperStingConverter() },//将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。 WriteIndented = true, }; WeatherForecastWithEnum wf=new WeatherForecastWithEnum(); string wfw= JsonSerializer.Serialize(wf, op); WeatherForecastWithEnum wff=JsonSerializer.Deserialize<WeatherForecastWithEnum>(wfw,op); Console.WriteLine( wfw); public class MYEnumToUpperStingConverter : JsonConverter<Summary> { public override Summary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return (Summary)Enum.Parse(typeToConvert, reader.GetString()); } public override void Write(Utf8JsonWriter writer, Summary value, JsonSerializerOptions options) { writer.WriteStringValue( Enum.GetName(value)); } } public class WeatherForecastWithEnum { public DateTimeOffset Date { get; set; } = DateTime.Now; public int TemperatureCelsius { get; set; } = new Random().Next(1000); [JsonConverter(typeof(MYEnumToUpperStingConverter))]//将 [JsonConverter] 特性应用于需要自定义转换器的属性。 public Summary Summaryp { get; set; } = Summary.Cold; [JsonConverter(typeof(MYEnumToUpperStingConverter))] public Summary Summaryp2 { get; set; } = Summary.Cold; } public enum Summary { Cold, Cool, Warm, Hot }
类型上的 [JsonConverter]
- 将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。
- 将 [JsonConverter] 属性应用于表示自定义值类型的类或结构。
using System.Text.Json; using System.Text.Json.Serialization; namespace SystemTextJsonSamples; public class test { static void Main() { Weather weather = new Weather(); JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true, }; string tem= JsonSerializer.Serialize(weather, options); Console.WriteLine(tem); Weather weather2 = JsonSerializer.Deserialize<Weather>(tem); Console.Read(); } } /* 输出 { "Temperatur": "23C" }*/ //解析 之所能输出这个结果 是因为序列化和反序列化时,类型的[JsonConverter(typeof(TemperatureConverter))] 特性在起作用
如果类型不加特性[JsonConverter(typeof(TemperatureConverter))] 将输出以下结果:
{
"Temperatur": {
"Degrees": 23,
"IsCelsius": true,
"IsFahrenheit": false
}
}
public class Weather { public Temperature Temperatur { get; set; } = new Temperature(23, true); } [JsonConverter(typeof(TemperatureConverter))] public struct Temperature { public Temperature(int degrees, bool celsius) { Degrees = degrees; IsCelsius = celsius; } public int Degrees { get; } public bool IsCelsius { get; } public bool IsFahrenheit => !IsCelsius; public override string ToString() => $"{Degrees}{(IsCelsius ? "C" : "F")}"; public static Temperature Parse(string input) { int degrees = int.Parse(input.Substring(0, input.Length - 1)); bool celsius = input.Substring(input.Length - 1) == "C"; return new Temperature(degrees, celsius); } } public class TemperatureConverter : JsonConverter<Temperature> { public override Temperature Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => Temperature.Parse(reader.GetString()!); public override void Write(Utf8JsonWriter writer, Temperature temperature, JsonSerializerOptions options) => writer.WriteStringValue(temperature.ToString()); }
编程是个人爱好