【问题标题】:Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?为什么 System.Text Json Serializer 不序列化这个通用属性但 Json.NET 呢?
【发布时间】:2020-05-26 23:51:18
【问题描述】:

我有以下情况。我把问题简化为下面的例子,虽然我的实际情况比较复杂。

System.Text.Json 不会完全序列化对象,但 Newtonsoft Json.NET 会。

假设我有以下类结构。

public class A
{
    public string AProperty { get; set; } = "A";
}

public class A<T> : A where T : class, new()
{
    public T TObject { get; set; } = new T();
}

public class B
{
    public string BProperty { get; set; } = "B";
}

public class B<T> : B where T : class, new()
{
    public T TObject { get; set; } = new T();
}

public class C
{
    public string CProperty { get; set; } = "C";
}

这是一个简单的 .NET Core 程序:

public class Program
{
    private static void Main(string[] args)
    {
        var obj = new A<B> { TObject = new B<C>() };

        var systemTextSerialized = JsonSerializer.Serialize(obj);
        var newtonsoftSerialized = JsonConvert.SerializeObject(obj);
    }
}

序列化结果如下:

System.Text.Json

{
  "TObject": {
    "BProperty": "B"
  },
  "AProperty": "A"
}

牛顿软件

{
  "TObject": {
    "TObject": {
      "CProperty": "C"
    },
    "BProperty": "B"
  },
  "AProperty": "A"
}

由于我的应用程序的结构,我不知道B 的泛型参数。我只知道是A&lt;B&gt;B 的实际 TObject 直到运行时才知道。

为什么这两种序列化方法不同?有没有办法让 System.Text.Json 完全序列化对象,还是我需要编写自定义转换器?

【问题讨论】:

  • 您可以编写自定义转换器或等待 .NET 5 发布
  • 因为 JSON.Net 更好

标签: c# .net-core json.net system.text.json


【解决方案1】:

这是System.Text.Json 的记录限制。来自docs

序列化派生类的属性

不支持多态类型层次结构的序列化。例如,如果将属性定义为接口或抽象类,则仅定义的属性对接口或抽象类进行序列化,即使运行时类型具有附加属性。此行为的例外情况将在本节中解释......

要序列化 ​​[a] 派生类型的属性,请使用以下方法之一:

  1. 调用允许您在运行时指定类型的 Serialize 重载...

  2. 将要序列化的对象声明为object

在您的情况下,A&lt;B&gt;.TObject 被声明为B 类型,但在您构造的实例中实际上是B&lt;C&gt; 类型,因此只有基类B 的属性根据文档进行序列化.就是这样。如需进一步讨论,请参阅已关闭的问题 System.Text.Json.JsonSerializer doesn't serialize properties from derived classes #31742

但是,有几种解决方法可用。首先,您可以将obj 构造为其最可能派生的类型A&lt;B&lt;C&gt;&gt;

var obj = new A<B<C>> { TObject = new B<C>() };

现在TObject 的所有属性都被序列化了。演示小提琴#1 here。但不幸的是,您不能使用此解决方法,因为 B 的实际 TObject 直到运行时才知道。

或者,如果您只需要序列化您的 obj,您可以按照文档中的建议 #2 并声明一个 object 类型的代理属性,然后将其序列化:

public class A<T> : A where T : class, new()
{
    [System.Text.Json.Serialization.JsonPropertyName("TObject")]
    [Newtonsoft.Json.JsonIgnore]
    public object SerializedTObject => TObject;

    [System.Text.Json.Serialization.JsonIgnore]
    public T TObject { get; set; } = new T();
}

请注意,不能为要序列化的只读属性设置JsonSerializerOptions.IgnoreReadOnlyProperties

演示小提琴#2 here.

最后,如果你需要多态序列化和反序列化,你需要写一个自定义的JsonConverter。开始看

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    • 2016-09-07
    • 1970-01-01
    • 2012-11-28
    相关资源
    最近更新 更多