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

2023-12-05

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

有3个班级。基地是Shape。继承的有Box and Circle.

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

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

我想了解的是-这是否是实现此类功能的最佳方法。确实,序列化的输出结果相当难看(我在下面的示例中添加了注释)。我不确定它是否以最好的方式完成,无论如何它正在发挥作用。

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

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


更新.Net 7

最新的.Net 7中引入了多态序列化/反序列化:

[JsonDerivedType(typeof(InheritedClass), "InheritedClass")]
public class BaseClass {};

这将正确序列化所有实例InheritedClass无论它们是顶级属性、对象本身还是属性层次结构的深处。

较旧的答案

这对我来说效果很好(在.Net 5中):

JsonSerializer.Serialize<object>(myInheritedObject)

然后包含基类和继承类的所有属性。但不确定这种方法是否有任何问题......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 .NET Core System.Text.Json 序列化/反序列化类层次结构 的相关文章

  • 通过另一个列表更新列表(linq)

    我有类 Data 的对象列表 如下所示 class Data int code string name DateTime date update 我还有另一个课程列表 例如 class RefCodes int old code int n
  • C# 和月历,选择多个日期

    我正在制作一个程序 可以帮助人们用 C 为某个部门 预订 订单 他们需要能够选择不同月份的多个日期 我更愿意拥有它 这样他们就可以单击一个日期 然后按住 Shift 键单击另一个日期以选择这两个日期之间的所有日期 并控制单击以进行单选 取消
  • libtool 在 Ubuntu 13.04 上构建 thrift 0.9.1 时出错

    在 Ubuntu 13 04 上构建 thrift 0 9 1 支持 C C java C perl python 时出现此错误 configure 不带任何选项运行 make 不带任何选项运行 Making all in test mak
  • 类中是否可以有虚拟类声明?

    我正在为个人项目中框架的各个组件设置一个接口 我突然想到了一些我认为可能对接口有用的东西 我的问题是这是否可能 class a public virtual class test 0 class b public a public clas
  • JSONP 使用 JQuery 从 HTTPS 协议获取 JSON

    我正在尝试获取从 https 安全站点发送的 JSON 客户端希望不要使用任何服务器端语言 全部都是 Javascript 我读到 当使用 Jquery 中的 ajax 函数时 我必须使用 JSONP 才能从安全站点加载 JSON 我的第一
  • 名称查找、实例化点 (POI) 和基本类型

    以下代码针对 X 进行编译 但不适用于 double struct X void foo double void foo X namespace NN struct A void foo A foo double error foo not
  • 编写具有多种类型的泛型扩展方法时的类型推断问题

    我正在为 IEnumerable 编写一个通用扩展方法 用于将对象列表映射到另一个映射对象列表 这就是我希望该方法的工作方式 IList
  • 从点云检测平面集

    我有一组点云 我想测试3D房间中是否有角落 所以我想讨论一下我的方法 以及在速度方面是否有更好的方法 因为我想在手机上测试它 我将尝试使用霍夫变换来检测线 然后我将尝试查看是否有三条线相交 并且它们也形成了两个相交的平面 如果点云数据来自深
  • 是否可以在Linux上将C转换为asm而不链接libc?

    测试平台为Linux 32位 但也欢迎 Windows 32 位上的某些解决方案 这是一个c代码片段 int a 0 printf d n a 如果我使用 gcc 生成汇编代码 gcc S test c 然后我会得到 movl 0 28 e
  • 如何使用 C# 查询远程 MS ACCESS .mdb 数据库

    我正在尝试使用 C 查询 mote MS ACCESS 数据库 mdb 文件 将文件复制到本地计算机时可以成功查询它 我只想远程放置文件 所以我的客户端程序不包含原始数据 static string m path http www xyz
  • 将 2 个字节转换为整数

    我收到一个 2 个字节的端口号 最低有效字节在前 我想将其转换为整数 以便我可以使用它 我做了这个 char buf 2 Where the received bytes are char port 2 port 0 buf 1 port
  • 在 C++ 代码 gdb 中回溯指针

    我在运行 C 应用程序时遇到段错误 在 gdb 中 它显示我的一个指针位置已损坏 但我在应用程序期间创建了 10 万个这样的对象指针 我怎样才能看到导致崩溃的一个 我可以在 bt 命令中执行任何操作来查看该指针的生命周期吗 谢谢 鲁奇 据我
  • 如何对STL向量进行排序?

    我想排序一个vector vector
  • 如何测试某些代码在 C++ 中无法编译? [复制]

    这个问题在这里已经有答案了 可能的重复 单元测试编译时错误 https stackoverflow com questions 605915 unit test compile time error 我想知道是否可以编写一种单元测试来验证给
  • 如何使用Gson仅从Json反序列化某些特定字段?

    我有以下 JSON 字符串 channel bvmt initValues data value instrumentIds TN0007250012 TN0007500010 instruments mnemonic ADWYA marc
  • 用数组或向量实现多维数组

    我想使用单个数组或向量实现多维数组 可以像通常的多维数组一样访问它 例如 a 1 2 3 我陷入困境的是如何实施 操作员 如果数组的维数为 1 则 a 1 应该返回位于索引 1 处的元素 但是如果维数大于一怎么办 对于嵌套向量 例如 3 维
  • 与 Entity Framework Core 2.0 的一对零关系

    我正在使用 C 和 NET Framework 4 7 将 Entity Framework 6 1 3 Code First 库迁移到 Entity Framework Core 我一直在用 Google 搜索 Entity Framew
  • 当 Verb="runas" 时设置 ProcessStartInfo.EnvironmentVariables

    我正在开发一个 C 应用程序 我需要创建变量并将其传递给新进程 我正在使用ProcessStartInfo EnvironmentVariables 新进程必须提升运行 因此我使用 Verb runas var startInfo new
  • 解释这段代码的工作原理;子进程如何返回值以及在哪里返回值?

    我不明白子进程如何返回该值以及返回给谁 输出为 6 7 问题来源 http www cs utexas edu mwalfish classes s11 cs372h hw sol1 html http www cs utexas edu
  • 意外的令牌:尝试解析 JSON 字符串时

    我正在尝试解析这个 JSON 字符串 RESULTS name Thessaloniki GR type Sailing l sailing weather beach Porto 20Carras 20Marina 45904 name

随机推荐

  • 如何在 Exoplayer 中添加下一个、上一个、快退和前进的侦听器

    我正在 ExoPlayer 上工作 我想自定义 ExoPlayer 并监听事件下一个 上一个 倒带 前进 以便当用户单击下一个按钮时播放列表中的下一个视频将播放 而使用上一个时将播放播放列表中的上一个视频将播放播放列表等 我正在使用自定义布
  • 有没有办法回答(或忽略)所有 y/n 提示的“y”?

    我有一个 Jupyter 笔记本 里面有很多大变量 有一次我想扔掉所有我已经用完的变量 我使用 reset selective 变量名来清除每个变量 但这些变量有 60 个 当我运行包含所有 60 个提示的块时 它会要求我为每个清除输入 y
  • 使用c#在Word中按名称访问表

    我有一个包含很多表格的文档 我想使用 C 和 Microsoft Office Interop Word 修改这些表 我读到我可以使用 Tables 接口迭代所有表 问题 是否可以为表指定名称 ID 并通过名称访问表 就像 Powerpoi
  • 通过 github API 关闭拉取请求

    根据我们应用程序的设计要求 我们曾经使用 gitlab API 删除 Gitlab 中的合并请求 现在我们正在迁移到 Github 我正在寻找类似的 API 调用来关闭 Github 上的拉取请求 我通读了文档here 但它没有回答我的问题
  • 对数据框的每一行进行排序[重复]

    这个问题在这里已经有答案了 我正在尝试使用这一行对数据框的每一行进行排序 sapply df function x sort x 但是 对列进行排序而不是对行进行排序 例如 这个数据框 5 10 7 1 5 6 3 9 2 4 4 5 1
  • *a, b, c = line.split() 中的星号有什么作用?

    Assume line is Chicago Sun 01 52 什么是 a b c line split 做 特别是 星号的意义是什么 编辑 经过测试 似乎 Chicago Sun and 01 52 都存储在a b and c 星号似乎
  • 一级缓存可以与 ICriteria 或其他 API 一起使用吗?

    In NHibernate使用时您可以轻松地从一级缓存中受益Load or Get方法 但是关于ICriteria HQL Linq to NHibernate and QueryOver 他们也使用一级缓存吗 他们使用它来返回实体 但查询
  • PowerMockito.doReturn 返回 null

    这是我正在测试的课程 public class A public Integer callMethod return someMethod private Integer someMethod Some Code HttpPost http
  • 在Linux上,如何确保解锁被锁定在死亡/终止的线程中的互斥体?

    这是一道面试题 在 Linux 上 如何确保解锁被锁定在死亡 终止的 POSIX 线程中的 POSIX 互斥锁 我的想法 Linux向程序发送kill或终止信号时会自动释放它吗 但是 我找不到有关操作系统如何执行此操作的更多详细信息 tha
  • Facebook.php 和 facebookapi_php5 文档

    我在哪里可以找到关于这两个 PHP 文件的良好文档以及每个函数的更详细和深入的使用 Facebook 文档 信息不够丰富 哈哈 我感受到你的痛苦 facebookapi php5主要是各个API方法 facebook 主要用于会话 身份验证
  • 如何动态添加新方法到 php 对象?

    如何 即时 向对象添加新方法 me new stdClass me gt doSomething function echo I ve done something me gt doSomething Fatal error Call to
  • Cordova 文件插件在 Android 中从未准备就绪

    我有一个非常简单的 Cordova 应用程序 只有一个插件 org apache cordova file 当我在 Android 模拟器中模拟该应用程序时 deviceready事件永远不会被触发 我得到以下输出 D CordovaLog
  • Zend Framework 2 - 注释表单不起作用

    谢谢 光新藤我调查了AnnotationForms这似乎是最好的解决方法ModelForms 但示例所示here对我不起作用 use Zend Form Annotation AnnotationBuilder builder new An
  • 构建项目时出现转换异常[重复]

    这个问题在这里已经有答案了 当我尝试运行我的应用程序时 出现以下错误 Error Execution failed for task app transformClassesWithDexForDebug gt com android bu
  • 绑定和解构块参数

    在 ruby 中 有没有一种方法可以同时将块的参数绑定到局部变量并对其进行解构 谷歌搜索没有找到我任何东西 并且在 IRB 中玩也毫无结果 但我想我回想起了类似于以下功能的功能 gt gt 1 2 3 4 map x y z x y z g
  • 将 DateTime.Add(TimeSpan) 与 LINQ 结合使用

    我必须运行如下查询 它实际上更复杂 但这里是重要的部分 var results from b in context Bookings where b ScheduleDate Add b StartTime gt DateTime UtcN
  • 批次中的随机生成器

    我有一个bat文件 echo RANDOM 并使用命令行执行它 start randomcheck bat start randomcheck bat 打开两个控制台 并且都包含相同的数字 4645 这无法达到随机的目的提供不同的临时文件夹
  • ASP.Net Core 文件上传进度会话

    我正在 ASP Net Core 中编写文件上传 并尝试更新进度栏 但是当从 javascript 调用 进度 操作时 会话值未正确更新 进度使用以下方式保存在用户会话中 public static void StoreInt ISessi
  • 如何在 Windows 上使用 python 2.6 安装 pip

    我尝试在我的开发计算机上安装带有 python 2 6 的 pip 以尝试匹配也使用 python 2 6 的部署环境 Python 2 6 安装正常 我尝试使用 get pip py 安装 pip 如此处所述https pip pypa
  • 使用 .NET Core System.Text.Json 序列化/反序列化类层次结构

    我有一个简单的类层次结构 我想使用 System Text Json 对其进行序列化 有3个班级 基地是Shape 继承的有Box and Circle 我计划在我的前端应用程序上使用这些类作为标记联合 所以我刚刚引入了一个鉴别器属性Tag