【问题标题】:Custom JSON Deserialization in C# with JsonConverter使用 JsonConverter 在 C# 中自定义 JSON 反序列化
【发布时间】:2021-02-06 05:02:19
【问题描述】:

我在 .Net Core 中有两个类

班级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
    }
}

我需要使用TimeSpan.FromTicks(Int64)TimeSpan.Ticks 方法将MeanInterval 显示为长刻度。

我的自定义 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();
        }
    }
}

我不知道如何实现Read 方法。 如何实现覆盖 Read 方法的自定义反序列化?

如果可以的话,你们向我提议CanConvert 方法的另一个实现,非常感谢。

【问题讨论】:

  • 您能否修改您的 Ownership 模型以添加 System.Text.Json 属性,或者对于此问题,该模型实际上是只读的?
  • @dbc 最好不要修改类,因为一方面我必须获得 JSON 格式,另一方面使用另一种 JSON 格式。如果我将类更改为设置单​​一 JSON 格式,则无法设置其他 JSON 格式。

标签: c# deserialization system.text.json jsonconverter


【解决方案1】:

您似乎只想执行TimeSpan 的自定义序列化,因为它属于Ownership,那么为什么不只为TimeSpan 制作一个转换器并避免手动序列化所有其他类属性呢?:

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);
    }
}

然后用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

【讨论】:

  • 嗨,约翰,非常感谢!,很好的答案。但不幸的是,我删除了另一个具有TimeSpan 属性的类,stackoverflow.com/q/66072157/5113188,I 需要专门将其应用为Ownership 类的属性,因为另一个Owner 类具有TimeSpan 的另一个属性。检查 System.Text.Json.Serialization.Json JsonConverter&lt;T&gt; 类仅包含 CanConvertReadWrite 方法..
  • @QA_Col 请参阅this fiddle,了解使用它时如何工作的更新示例。您可以看到只有应用了属性的属性才会受到转换器的影响。我还更正了对 System.Text.Json 而不是 Json.NET 的回答(我之前的错误,抱歉)。
【解决方案2】:

我的回复(很长一段路),您可以选择何时应用自定义转换器。 其他相关帖子: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();
        }
    }
}

我的测试

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();
    }
}

输出:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 2014-08-02
    • 2019-06-03
    相关资源
    最近更新 更多