【C# 序列化】 自定义Json转换器模式

【C# 序列化】 自定义Json转换器

https://docs.microsoft.com/zh-cn/dotnet/standard/serialization/system-text-json-converters-how-to?pivots=dotnet-6-0

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 或开放式泛型的转换器。 基本模式适用于非泛型或封闭式泛型类型。 例如,适用于以下类型的转换器需要工厂模式:

可以通过基本模式处理的类型的一些示例包括:

  • Dictionary<int, string>
  • WeekdaysEnum
  • List<DateTimeOffset>
  • DateTime
  • Int32

基本模式创建的类可以处理一种类型。 工厂模式创建的类在运行时确定所需的特定类型,并动态创建适当的转换器。

自定义基本模式转换器

遵循基本模式的步骤

以下步骤说明如何遵循基本模式来创建转换器:

  • 创建一个派生自 JsonConverter<T> 的类,其中 T 是要进行序列化和反序列化的类型。
  • 重写 Read 方法,以反序列化传入 JSON 并将其转换为类型 T。 使用传递给方法的 Utf8JsonReader 读取 JSON。 无需担心处理部分数据,因为序列化程序会传递当前 JSON 范围的所有数据。 因此,不需要调用 SkipTrySkip,也不需要验证 Read 是否返回 true
  • 重写 Write 方法以序列化 T 类型的传入对象。 使用传递给方法的 Utf8JsonWriter 写入 JSON。
  • 仅当需要时才重写 CanConvert 方法。 当要转换的类型属于类型 T 时,默认实现会返回 true。 因此,仅支持类型 T 的转换器不需要重写此方法。 有关的确需要重写此方法的转换器的示例,请参阅本文后面的多态反序列化部分。

 可以参阅内置转换器源代码作为用于编写自定义转换器的参考实现。

属性上的 [JsonConverter]

  1. 将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。
  2. 将 [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]

  1. 将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。
  2.  将 [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()); }

 

posted @ 2022-03-22 01:23  小林野夫  阅读(1859)  评论(0编辑  收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/