为什么 System.Text Json 序列化程序不序列化此泛型属性,但 Json.NET 序列化?



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

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

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

这是记录在案的System.Text.Json限制。 从文档中:

序列化派生类的属性

在 .NET 7 之前的版本中,System.Text.Json不支持多态类型层次结构的序列化。例如,如果将属性定义为接口或抽象类,则仅序列化在接口或抽象类上定义的属性,即使运行时类型具有其他属性也是如此。本节介绍了此行为的例外情况。

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

  1. 调用序列化的重载,允许您在运行时指定类型...

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

现在,TObject的所有属性都已序列化。 演示小提琴#1在这里。 但不幸的是,您不能使用此解决方法,因为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在这里。

最后,如果需要多态序列化和反序列化,则需要编写自定义JsonConverter或(在 .NET 7 及更高版本中(使用适当的属性批注标记基类型。 要开始使用,请参阅

  • 在System.Text.Json中可以进行多态反序列化吗?
  • 使用 .NET Core System.Text.Json 序列化/反序列化类层次结构
  • System.Text.Json 和动态解析多态对象

最新更新