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

标签 c# .net-core json.net 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";
}

这是一个简单的 .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);
    }
}

序列化结果如下:

系统.Text.Json
{
  "TObject": {
    "BProperty": "B"
  },
  "AProperty": "A"
}


牛顿软件
{
  "TObject": {
    "TObject": {
      "CProperty": "C"
    },
    "BProperty": "B"
  },
  "AProperty": "A"
}

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

为什么这两种序列化方法不同?有没有办法让 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>在你构造的实例中,只有基类的属性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 .但不幸的是,您无法使用此解决方法,因为实际 TObjectB直到运行时才知道。
或者,如果您只需要序列化您的 obj ,您可以按照文档中的建议 #2 并声明 object -typed 代理属性,并将其序列化:
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 .开始看
  • 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 .
  • 关于c# - 为什么 System.Text Json Serializer 不会序列化这个通用属性,但 Json.NET 会?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62033264/

    相关文章:

    angular - spa.UseAngularCliServer() 中间件如何为网页提供服务?

    c# - 使用 Json.NET 反序列化包含数字键的 JSON

    c# - Json.net 反序列化错误(JSONReaderException)

    c# - 保持 UI 线程空闲

    c# - (num % 2) 可以得到 0、1 等等?在 C#

    C# 从 "parent project"中的 "child project"访问一个类?

    azure - 使用控制台应用程序 webjob 轮询存储队列中的消息

    .net-core - 为什么用类声明比用结构体声明需要更多内存?

    c# - 无效的属性标识符字符 : ‘. Path ' ', 第 1 行,将 json 字符串解析为对象时的位置 1

    c# - 高质量图像缩放库