为什么 System.Text Json 序列化器不序列化这个泛型 属性 而 Json.NET 序列化?

Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?

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

System.Text.Json 没有完全序列化对象,但 Newtonsoft Json.NET 可以。

假设我有以下 class 结构。

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<B>B 的实际 TObject 直到运行时才知道。

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

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

Serialize properties of derived classes

Serialization of a polymorphic type hierarchy is not supported. For example, if a property is defined as an interface or an abstract class, only the properties defined on the interface or abstract class are serialized, even if the runtime type has additional properties. The exceptions to this behavior are explained in this section....

To serialize the properties of [a] derived type, use one of the following approaches:

  1. Call an overload of Serialize that lets you specify the type at runtime...

  2. Declare the object to be serialized as object.

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

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

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

现在 TObject 的所有属性都被序列化了。演示 fiddle #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

演示 fiddle #2 here.

最后,如果需要多态序列化和反序列化,则需要编写自定义JsonConverter。要开始使用,请参阅

  • Serialize/Deserialize a class hierarchy with .NET Core System.Text.Json
  • .