为什么System.Text Json Serialiser不能序列化该通用属性,而Json.NET可以序列化呢? [英] Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?

查看:136
本文介绍了为什么System.Text Json Serialiser不能序列化该通用属性,而Json.NET可以序列化呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following situation. I have simplified the problem into the following example, although my real situation is more complicated.

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

System.Text.Json does not serialise the object fully but Newtonsoft Json.NET does.

假设我具有以下类结构.

Suppose I have the following class structure.

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程序:

Here is a simple .NET Core program:

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

序列化结果如下:

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

Newtonsoft

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

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

Due to the structure of my application, I don't know the generic parameter of B. I only know that it is an A<B>. The actual TObject of B is not known until runtime.

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

Why do these two serialisation methods differ? Is there a way to get System.Text.Json to serialise the object fully, or do I need to write a custom converter?

推荐答案

这是记录在案的System.Text.Json限制.从

This is a documented limitation of System.Text.Json. From the 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 the derived type in the preceding example, use one of the following approaches:

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

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

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

Declare the object to be serialized as object.

在您的情况下,A<B>.TObject被声明为类型B,但实际上在您构造的实例中为类型B<C>,因此根据文档,只有基类B的属性才被序列化.就是这样.有关进一步的讨论,请参见封闭的问题 System.Text.Json.JsonSerializer不会序列化属性来自派生类#31742 .

In your case A<B>.TObject is declared to be of type B but is actually of type B<C> in the instance you construct, so only the properties of the base class B are getting serialized as per the documentation. So that's that. For further discussion see the closed issue System.Text.Json.JsonSerializer doesn't serialize properties from derived classes #31742.

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

There are several workarounds available, however. Firstly, you could construct obj as its most possibly derived type A<B<C>>:

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

现在TObject的所有属性都将被序列化.演示小提琴#1 此处.但是很遗憾,您无法使用此替代方法,因为 B的实际TObject直到运行时才知道.

Now all properties of TObject get serialized. Demo fiddle #1 here. But unfortunately you can't use this workaround since The actual TObject of B is not known until runtime.

或者,如果您只需要序列化obj ,则可以遵循文档中的建议2,并声明一个object类型的代理属性,并对其进行序列化:

Alternatively, if you only need to serialize your obj, you could follow suggestion #2 from the docs and declare an object-typed surrogate property, and serialize that:

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();
}

请注意,

Note that JsonSerializerOptions.IgnoreReadOnlyProperties must not be set for read-only properties to be serialized.

演示小提琴#2 此处.

最后,如果您需要多态序列化和反序列化,则需要编写自定义

Finally, if you need polymorphic serialization and deserialization, you will need to write a custom JsonConverter. To get started see

  • Is polymorphic deserialization possible in System.Text.Json?
  • Serialize/Deserialize a class hierarchy with .NET Core System.Text.Json
  • System.Text.Json and Dynamically Parsing polymorphic objects.

这篇关于为什么System.Text Json Serialiser不能序列化该通用属性,而Json.NET可以序列化呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆