为什么System.Text Json Serialiser不能序列化该通用属性,而Json.NET可以序列化呢? [英] Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?
问题描述
我有以下情况.尽管我的实际情况更加复杂,但我已将问题简化为以下示例.
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?
推荐答案
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:
-
调用Serialize的重载,可让您在运行时指定类型...
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
- 在System.Text.Json中可以进行多态反序列化吗?
- 使用.NET Core System.Text.Json 对类层次结构进行序列化/反序列化>
- System.Text.Json和动态解析多态对象 .
- 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屋!