【问题标题】:System.Text.Json Serialization BehaviourSystem.Text.Json 序列化行为
【发布时间】:2020-12-29 11:27:43
【问题描述】:

我有 3 节课;它们以下列方式相互包含:

TestClass1
    - TestClass2
        - TestClass3
        - TestClass3
    - TestClass2
        - TestClass3
        - TestClass3

我要做的是序列化然后反序列化这个类结构。

以下是课程:

class TestClass1
{
    public List<object> Data { get; set; }
}

class TestClass2
{
    public string Data1 { get; internal set; }
    public TestClass3 Data2 { get; internal set; }
}

public TestClass3(DateTime dateTime, string v1, string v2, int v3)
{
    this.dateTime = dateTime;
    this.v1 = v1;
    this.v2 = v2;
    this.v3 = v3;
}

我正在运行的代码在这里:

var data = new List<TestClass2>()
{
    new TestClass2()
    {
        Data1 = "test1",
        Data2 = new TestClass3(new DateTime(2021, 02, 05), "Test", "Test2", 1234)
    },
    new TestClass2()
    {
        Data1 = "test2",
        Data2 = new TestClass3(new DateTime(2021, 02, 06), "Test", "Test3", 1234)
    },
    new TestClass2()
    {
        Data1 = "test1",
        Data2 = new TestClass3(new DateTime(2021, 02, 07), "Test23", "Test2", 5545)
    },
};

var dataStream = new TestClass1()
{
    Data = data.Select(a => (object)a).ToList(),                
};

var streamSerialized = JsonSerializer.Serialize(dataStream);

var objects = JsonSerializer.Deserialize<TestClass1>(streamSerialized);

这里有两个问题

首先,对象没有正确序列化streamSerialized 不包含TestClass2.Data2 的任何数据。其次,当我反序列化时,它没有正确反序列化到类结构中——也就是说,如果我这样做:

var class2 = (TestClass2)objects.Data.First();

我收到此错误:

System.InvalidCastException:'无法将'System.Text.Json.JsonElement'类型的对象转换为'ConsoleApp1.TestClass2'类型

【问题讨论】:

  • 序列化器不知道如何将object 类型列表反序列化为TestClass2 类型列表。
  • 您不能将object 与序列化程序一起使用。您需要显式使用您期望的类型,或者如果类型为“未知”,则手动读取和写入 JsonElement 上的属性。这是一项安全功能。
  • public List&lt;object&gt; Data 为什么在这里使用object
  • 如果我将 public List&lt;object&gt; Data 更改为 public List&lt;TestClass2&gt; Data 我仍然没有得到任何序列化(streamSerialized Data2 仍然为空)
  • 我错过了什么?看起来不错dotnetfiddle.net/QPrFCA

标签: c# .net serialization system.text.json


【解决方案1】:

反序列化工作基于作为泛型参数提供给Deserialize() 的类型,并且对原始类型一无所知。

如果你拿调试器,你可以看到会发生什么:

你序列化为 json。 JSON 不包含有关原始类型的任何信息:

var streamSerialized = JsonSerializer.Serialize(dataStream);

你反序列化它并告诉 JsonSerializer 使用来自TestClass1的信息:

var objects = JsonSerializer.Deserialize<TestClass1>(streamSerialized);

TestClass1 告诉 JsonSerializer 所有列表项都是objects:

class TestClass1
{
    public List<object> Data { get; set; }
}

没有什么能让序列化程序知道列表项的类型应该是TestClass2,因此它会反序列化为 JsonElements 列表 (https://docs.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement?view=net-5.0)

... 并且 JsonElement 不能强制转换为 TestClass2。

第一次修复

public List<TestClass2> Data

现在看看你的TestClass2

class TestClass2
{
    public string Data1 { get; internal set; }
    public TestClass3 Data2 { get; internal set; }
}

Setter 是内部的,因此值将为空。提供构造函数或将它们公开。

class TestClass2
{
    public string Data1 { get; set; }
    public TestClass3 Data2 { get; set; }
}

构造函数用法见:https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-immutability?pivots=dotnet-5-0

有关一般行为的更多详细信息,请参阅文档:https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-5-0#deserialization-behavior

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 2021-07-17
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多