为什么 System.Text Json Serialiser 不会序列化这个通用属性,但 Json.NET 会?

Row*_*man 5 c# json.net .net-core system.text.json

我有以下情况。我已经将问题简化为以下示例,尽管我的实际情况更复杂。

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";
}
Run Code Online (Sandbox Code Playgroud)

这是一个简单的 .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);
    }
}
Run Code Online (Sandbox Code Playgroud)

序列化结果如下:

系统.Text.Json

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

Run Code Online (Sandbox Code Playgroud)

牛顿软件

{
  "TObject": {
    "TObject": {
      "CProperty": "C"
    },
    "BProperty": "B"
  },
  "AProperty": "A"
}
Run Code Online (Sandbox Code Playgroud)

由于我的应用程序的结构,我不知道B. 我只知道它是一个A<B>. 直到运行时才知道实际TObjectB

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

dbc*_*dbc 5

这是System.Text.Json. 从文档

序列化派生类的属性

不支持多态类型层次结构的序列化。例如,如果一个属性被定义为接口或抽象类,则只有在接口或抽象类上定义的属性才会被序列化,即使运行时类型具有附加属性。本节解释了此行为的例外情况....

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

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

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

在您的情况下A<B>.TObject被声明为类型,B但实际上是B<C>您构造的实例中的类型,因此只有基类的属性B按照文档进行序列化。所以就是这样。如需进一步讨论,请参阅已关闭的问题System.Text.Json.JsonSerializer 不会序列化派生类的属性 #31742

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

var obj = new A<B<C>> { TObject = new B<C>() };
Run Code Online (Sandbox Code Playgroud)

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

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

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();
}
Run Code Online (Sandbox Code Playgroud)

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

演示小提琴 #2在这里

最后,如果您需要多态序列化和反序列化,您将需要编写自定义JsonConverter. 开始看