使用 .NET Core System.Text.Json 序列化/反序列化类层次结构

编程入门 行业动态 更新时间:2024-10-27 18:19:05
本文介绍了使用 .NET Core System.Text.Json 序列化/反序列化类层次结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我有一个简单的类层次结构,我想使用 System.Text.Json 对其进行序列化.

I have a simple class hierarchy that I want to serialize using System.Text.Json.

有3个班级.基础是Shape.继承的是Box和Circle.

There are 3 classes. The base is Shape. Inherited ones are Box and Circle.

我计划在我的前端应用程序中使用这些类作为标记联合,因此我刚刚引入了鉴别器属性 Tag.

I have a plan to use these classes as a tagged union on my frontend app so I just introduced a discriminator property Tag.

我写了一个类型转换器,支持这个层次结构的序列化/反序列化.

I wrote a type convertor that supports serialization/deserialization of this hierarchy.

我想了解的是 - 这是否是实现此类功能的最佳方法.确实,序列化的输出结果非常难看(我在下面的示例中添加了注释).我不确定它是否以最好的方式完成,反正它只是在工作.

What I'm trying to understand - is this a best approach to implement such functionality or not. Indeed the output result of serialization is quite ugly (I put a comment in an example below). I'm not sure it's done the best way anyway it's just working.

这是我如何实现序列化/反序列化的示例:

Here's the example how I implemented serialization/deserialization:

using System; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; namespace Serialization.Theory { public abstract class Shape { public abstract String Tag { get; } } public class Box : Shape { public override String Tag { get; } = nameof(Box); public Single Width { get; set; } public Single Height { get; set; } public override String ToString() { return $"{Tag}: Width={Width}, Height={Height}"; } } public class Circle : Shape { public override String Tag { get; } = nameof(Circle); public Single Radius { get; set; } public override String ToString() { return $"{Tag}: Radius={Radius}"; } } public class ShapeConverter : JsonConverter<Shape> { public override Boolean CanConvert(Type typeToConvert) { return typeToConvert == typeof(Circle) || typeToConvert == typeof(Shape); } public override Shape Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { var raw = reader.GetString(); var doc = JsonDocument.Parse(raw); var prop = doc.RootElement.EnumerateObject().Where(x => x.Name == "Tag").First(); var value = prop.Value.GetString(); switch (value) { case nameof(Circle): return JsonSerializer.Deserialize<Circle>(raw); case nameof(Box): return JsonSerializer.Deserialize<Box>(raw); default: throw new NotSupportedException(); } } public override void Write(Utf8JsonWriter writer, Shape value, JsonSerializerOptions options) { if (value is Circle circle) { writer.WriteStringValue(JsonSerializer.SerializeToUtf8Bytes(circle)); } else if (value is Box box) { writer.WriteStringValue(JsonSerializer.SerializeToUtf8Bytes(box)); } } } class Program { static void Main(string[] args) { // Keep in base class references like it's a property on another object. Shape origin1 = new Box { Width = 10, Height = 20 }; Shape origin2 = new Circle { Radius = 30 }; var settings = new JsonSerializerOptions(); settings.Converters.Add(new ShapeConverter()); var raw1 = JsonSerializer.Serialize(origin1, settings); var raw2 = JsonSerializer.Serialize(origin2, settings); Console.WriteLine(raw1); // "{\u0022Tag\u0022:\u0022Box\u0022,\u0022Width\u0022:10,\u0022Height\u0022:20}" Console.WriteLine(raw2); // "{\u0022Tag\u0022:\u0022Circle\u0022,\u0022Radius\u0022:30}" var restored1 = JsonSerializer.Deserialize<Shape>(raw1, settings); var restored2 = JsonSerializer.Deserialize<Shape>(raw2, settings); Console.WriteLine(restored1); // Box: Width=10, Height=20 Console.WriteLine(restored2); // Circle: Radius=30 } } }

推荐答案

请试试我写的这个库作为 System.Text.Json 的扩展来提供多态:github/dahomey-technologies/Dahomey.Json

Please try this library I wrote as an extension to System.Text.Json to offer polymorphism: github/dahomey-technologies/Dahomey.Json

public abstract class Shape { } [JsonDiscriminator(nameof(Box))] public class Box : Shape { public float Width { get; set; } public float Height { get; set; } public override string ToString() { return $"Box: Width={Width}, Height={Height}"; } } [JsonDiscriminator(nameof(Circle))] public class Circle : Shape { public float Radius { get; set; } public override string ToString() { return $"Circle: Radius={Radius}"; } }

继承类必须手动注册到鉴别器约定注册表,以便让框架知道鉴别器值和类型之间的映射:

Inherited classes must be manually registered to the discriminator convention registry in order to let the framework know about the mapping between a discriminator value and a type:

JsonSerializerOptions options = new JsonSerializerOptions(); options.SetupExtensions(); DiscriminatorConventionRegistry registry = options.GetDiscriminatorConventionRegistry(); registry.RegisterConvention(new AttributeBasedDiscriminatorConvention<string>(options, "Tag")); registry.RegisterType<Box>(); registry.RegisterType<Circle>(); Shape origin1 = new Box { Width = 10, Height = 20 }; Shape origin2 = new Circle { Radius = 30 }; string json1 = JsonSerializer.Serialize(origin1, options); string json2 = JsonSerializer.Serialize(origin2, options); Console.WriteLine(json1); // {"Tag":"Box","Width":10,"Height":20} Console.WriteLine(json2); // {"Tag":"Circle","Radius":30} var restored1 = JsonSerializer.Deserialize<Shape>(json1, options); var restored2 = JsonSerializer.Deserialize<Shape>(json2, options); Console.WriteLine(restored1); // Box: Width=10, Height=20 Console.WriteLine(restored2); // Circle: Radius=30

更多推荐

使用 .NET Core System.Text.Json 序列化/反序列化类层次结构

本文发布于:2023-11-14 21:33:37,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1588554.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:序列化   层次   结构   Core   NET

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!