使用 JsonConverter 在 C# 中自定义 JSON 反序列化
Custom JSON Deserialization in C# with JsonConverter
我在 .Net Core 中有两个 classes
classOwnership
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
方法的另一种实现方式,非常感谢。
您似乎只想执行 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);
}
}
然后用 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
}
我的回答(很长的路要走),您可以在应用自定义转换器时选择。
其他相关帖子:post1, post2 and doc.
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
我在 .Net Core 中有两个 classes
classOwnership
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
方法的另一种实现方式,非常感谢。
您似乎只想执行 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);
}
}
然后用 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
}
我的回答(很长的路要走),您可以在应用自定义转换器时选择。 其他相关帖子:post1, post2 and doc.
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