简体   繁体   English

使用 JsonConverter 在 C# 中自定义 JSON 反序列化

[英]Custom JSON Deserialization in C# with JsonConverter

I have two classes in.Net Core我在.Net Core 中有两个课程

The class Ownership class Ownership

namespace CustomStoreDatabase.Models
{
    public class Ownership
    {
        public string OwnershipId { get; set; }
        public List<string> TextOutput { get; set; }
        public DateTime DateTime { get; set; }
        public TimeSpan MeanInterval { get; set; }// Like long ticks, TimeSpan.FromTicks(Int64), TimeSpan.Ticks
    }
}

I need to show MeanInterval like long ticks, using the methods TimeSpan.FromTicks(Int64) and TimeSpan.Ticks .我需要使用TimeSpan.FromTicks(Int64)TimeSpan.Ticks方法显示MeanInterval类的长刻度。

My custom JsonConverter我的自定义 JsonConverter

using CustomStoreDatabase.Models;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace CustomStoreDatabase.Util
{
    public class OwnershipJSonConverter : JsonConverter<Ownership>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return true;
        }

        public override Ownership Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartObject)
            {
                throw new JsonException();
            }
            //*******************
            // HOW TO IMPLEMENT?
            //*******************
            //throw new NotImplementedException();
        }

        public override void Write(Utf8JsonWriter writer, Ownership value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();
            if (value != null)
            {
                writer.WriteString("OwnershipId", value.OwnershipId);
                writer.WriteString("TextOutput", JsonSerializer.Serialize(value.TextOutput));
                writer.WriteString("DateTime", JsonSerializer.Serialize(value.DateTime));
                if (value.MeanInterval != null)
                {
                    writer.WriteNumber("MeanInterval", (long)value.MeanInterval.Ticks);
                }
                else
                {
                    writer.WriteNull("MeanInterval");
                }
            }
            writer.WriteEndObject();
        }
    }
}

I don't know how to implement the Read method.我不知道如何实现Read方法。 How can I implement the custom Deserialization overriding the Read method?如何实现覆盖 Read 方法的自定义反序列化?

If is possible you guys proposal to me another implementation for CanConvert method, I thank you very much.如果可能的话,你们向我建议CanConvert方法的另一种实现,非常感谢。

It seems like you only want to perform custom serialization of TimeSpan as it belongs to Ownership , so why not make a converter for TimeSpan only and save yourself from manually serializing all of the other class properties?:似乎您只想执行TimeSpan的自定义序列化,因为它属于Ownership ,所以为什么不只为TimeSpan制作一个转换器并避免手动序列化所有其他 class 属性?:

public class TimeSpanConverter : JsonConverter<TimeSpan>
{
    public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return TimeSpan.FromTicks(reader.GetInt64());
    }

    public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options)
    {
        writer.WriteNumberValue(value.Ticks);
    }
}

Then decorate your MeanInterval property with a JsonConverterAttribute :然后用JsonConverterAttribute装饰你的MeanInterval属性:

public class Ownership
{
    public string OwnershipId { get; set; }
    public List<string> TextOutput { get; set; }
    public DateTime DateTime { get; set; }
    [JsonConverter(typeof(TimeSpanConverter))]
    public TimeSpan MeanInterval { get; set; }// Like long ticks, TimeSpan.FromTicks(Int64), TimeSpan.Ticks
}

Try it online在线尝试

My response (long way), you can choose when apply the custom converter.我的回应(很长的路),您可以选择何时应用自定义转换器。 Others related posts: post1 , post2 and doc .其他相关帖子: post1post2doc

namespace CustomStoreDatabase.Util
{
    public class OwnershipJSonConverter : JsonConverter<Ownership>
    {
        public override bool CanConvert(Type typeToConvert)
        {
            return true;
        }

        public override Ownership Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType != JsonTokenType.StartObject)
            {
                throw new JsonException();
            }
            Ownership value = new Ownership();
            while (reader.Read())
            {
                //Console.WriteLine($"reader.TokenType:{reader.TokenType}");
                if (reader.TokenType == JsonTokenType.EndObject) {
                    //Console.WriteLine($"End Object!");
                    break;
                }
                switch (reader.TokenType)
                {
                    case JsonTokenType.PropertyName:
                        {
                            string propertyName = reader.GetString();
                            //Console.WriteLine($"propertyName:{propertyName}");
                            switch (propertyName)
                            {
                                case "OwnershipId":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null) {
                                            value.OwnershipId = reader.GetString();
                                        }
                                        break;
                                    }
                                case "TextOutput":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null)
                                        {
                                            value.TextOutput = JsonSerializer.Deserialize<List<string>>(reader.GetString());
                                        }
                                        break;
                                    }
                                case "DateTime":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null)
                                        {
                                            value.DateTime = JsonSerializer.Deserialize<DateTime>(reader.GetString());
                                        }
                                        break;
                                    }
                                case "MeanInterval":
                                    {
                                        reader.Read();
                                        if (reader.TokenType != JsonTokenType.Null)
                                        {
                                            value.MeanInterval = TimeSpan.FromTicks(reader.GetInt32());
                                        }
                                        break;
                                    }
                            }
                            break;
                        }
                }
            }
            return value;
        }

        public override void Write(Utf8JsonWriter writer, Ownership value, JsonSerializerOptions options)
        {
            writer.WriteStartObject();
            if (value != null)
            {
                writer.WriteString("OwnershipId", value.OwnershipId);
                writer.WriteString("TextOutput", JsonSerializer.Serialize(value.TextOutput));
                writer.WriteString("DateTime", JsonSerializer.Serialize(value.DateTime));
                if (value.MeanInterval != null)
                {
                    writer.WriteNumber("MeanInterval", (long)value.MeanInterval.Ticks);
                }
                else
                {
                    writer.WriteNull("MeanInterval");
                }
            }
            writer.WriteEndObject();
        }
    }
}

My test我的测试

public class Program
{
    public static void Main(string[] args)
    {
        var ownershipI = new Ownership() {
            OwnershipId = "--OwnershipId--",
            TextOutput = new List<string>()
            {
                "carrot",
                "fox",
                "explorer"
            },
            DateTime = DateTime.Now,
            MeanInterval = TimeSpan.FromSeconds(-0.05)
        };

        string jsonStringDefault = JsonSerializer.Serialize(ownershipI, new JsonSerializerOptions{
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        });
        Console.WriteLine($"jsonStringDefault:{jsonStringDefault}");

        var serializeOptions = new JsonSerializerOptions
        {
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
            Converters = { new OwnershipJSonConverter() }
        };
        string jsonStringCustomInput = JsonSerializer.Serialize(ownershipI, serializeOptions);
        Console.WriteLine($"jsonStringCustomInput:{jsonStringCustomInput}");
        Console.WriteLine($"Are jsonStringDefault and jsonStringCustomInput Equals?: {jsonStringDefault.Equals(jsonStringCustomInput)}");

        Ownership ownershipO  = JsonSerializer.Deserialize<Ownership>(jsonStringCustomInput, serializeOptions);
        string jsonStringCustomOutput = JsonSerializer.Serialize(ownershipO, serializeOptions);
        Console.WriteLine($"jsonStringCustomOutput:{jsonStringCustomOutput}");

        Console.WriteLine($"Are jsonStringCustomInput and jsonStringCustomOutput Equals?: :{jsonStringCustomInput.Equals(jsonStringCustomOutput)}");
        Console.WriteLine();
    }
}

The output: output:

jsonStringDefault:{
  "OwnershipId": "--OwnershipId--",
  "TextOutput": [
    "carrot",
    "fox",
    "explorer"
  ],
  "DateTime": "2021-02-08T03:13:47.0472512-05:00",
  "MeanInterval": {
    "Ticks": -500000,
    "Days": 0,
    "Hours": 0,
    "Milliseconds": -50,
    "Minutes": 0,
    "Seconds": 0,
    "TotalDays": -5.787037037037037E-07,
    "TotalHours": -1.388888888888889E-05,
    "TotalMilliseconds": -50,
    "TotalMinutes": -0.0008333333333333334,
    "TotalSeconds": -0.05
  }
}
jsonStringCustomInput:{
  "OwnershipId": "--OwnershipId--",
  "TextOutput": "[\"carrot\",\"fox\",\"explorer\"]",
  "DateTime": "\"2021-02-08T03:13:47.0472512-05:00\"",
  "MeanInterval": -500000
}
Are jsonStringDefault and jsonStringCustomInput Equals?: False
jsonStringCustomOutput:{
  "OwnershipId": "--OwnershipId--",
  "TextOutput": "[\"carrot\",\"fox\",\"explorer\"]",
  "DateTime": "\"2021-02-08T03:13:47.0472512-05:00\"",
  "MeanInterval": -500000
}
Are jsonStringCustomInput and jsonStringCustomOutput Equals?: :True

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM