如何将反序列化的 JSON 对象解析回数组?

How to parse deserialized JSON object back into arrays?

我已经成功地序列化了整个 class 属性(数组、字符串向量、整数、双精度数)。反序列化也可以,但我需要一种方法将返回的对象解析为各种数组,然后将这些设置为等于相同维度的四个数组。

以前,当我使用 BinaryFormatter 时,我可以简单地声明 mydeser As Object,反序列化为 mydeser,然后使用例如直接提取数组readarray = mydeser.array.

我注意到 JObject 是一种字典,但我不知道键是什么,值是某种 jsonToken。

我尝试使用:

For each kvp as KeyValuePair(String, jsonToken) in myser
Next

但是抛出了异常。那么有没有一种方法可以使用一个键,然后将 JObject 的值直接放入数组中,使用 maybe readarray = mydeser("array") —— 假设 mydeser 是一个字典?

Imports System.IO
Imports Newtonsoft.Json

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim ser As New testSer
    End Sub
End Class

Public Class testSer
    Public Property array As Double(,)
    Public Property vector As Double()
    Public Property strVec As String()
    Public Property IntVec As Integer()
    Sub New()
        serdeser()
    End Sub
    Sub serdeser()
        Dim r As New Random
        ReDim array(1000, 1000)
        ReDim vector(1000)
        ReDim strVec(1000)
        ReDim IntVec(1000)
        For i = 1 To 1000
            vector(i) = r.NextDouble
            strVec(i) = "A"
            IntVec(i) = r.Next(1, 100)
            For j = 1 To 1000
                array(i, j) = r.NextDouble
            Next
        Next

        Dim jsonSerializer As New JsonSerializer

        Dim stream As FileStream = File.Create("D:\test")
        Dim writer As New StreamWriter(stream)
        Dim jsonWriter As New JsonTextWriter(writer)
        jsonSerializer.Serialize(jsonWriter, Me)
        writer.Close()

        Dim stream1 As FileStream = File.Open("D:\test", FileMode.Open, FileAccess.Read, FileShare.Read)
        Dim reader As New StreamReader(stream1)
        Dim jsonTextReader As New JsonTextReader(reader)
        Dim mydeser As Linq.JObject
        mydeser = jsonSerializer.Deserialize(jsonTextReader)

        Dim readarray(1000, 1000) As Double
        Dim readvector(1000) As Double
        Dim readstrVec(1000) As String
        Dim readIntVec(1000) As Integer

        Dim mystr = DirectCast(mydeser.First, Linq.JProperty)
        'readarray = mydeser.array <--need to assign "array" back into readarray
        'readvector = mydeser.vector
        'readstrVec = mydeser.strvec
        'readarray = mydeser.intvec

        reader.Close()
    End Sub

End Class

一些建议,考虑到这是一个测试class:

  • 您的序列化过程大部分是正确的。最好用 Using 语句声明 Stream 对象,这样在发生异常时,这些对象将被隐式处理。

  • 只要指定反序列化的类型,反序列化就会变得非常简单。类型由您的 class 的类型表示。你可以只写(见示例代码):

    Dim myObject = [JsonSerializer].Deserialize(Of [MyObjectType])([JsonTextReader])
    
  • 您不需要 FileStream,StreamWriter / StreamReader 已经在内部使用了 FileStream。如果文件不存在,StreamWriter 会创建该文件。

  • StreamReader 使用 Encoding.UTF8 显式初始化:这是默认设置,只是一个余数,这是使用的编码,并且文件在没有 BOM 签名的情况下保存。

  • 在退出 Using 块之前,在 JsonTextWriter 上调用 Close()。该行为由 AutoCompleteOnClose 属性 决定,默认设置为 True 并且更安全。

  • 反序列化时,将JsonTextReader的FloatParseHandling属性设置为FloatParseHandling.DoubleFloatParseHandling.DecimalDouble 实际上是默认值,请记住这一点,以防您需要处理 Decimal 值,否则这些值将反序列化为 Double.

  • 数组的下界是0,不是1

  • 使您的 Random 对象成为静态字段。这确保了更好的功能(或者,如果需要,它可以让 class 正常运行)。

在修改后的示例 class 中,我重载了构造函数:传递 True,将调用 Build() 方法,用随机数据填充 class 对象.
传递 False,生成一个空对象。

不需要复制反序列化的值,您可以直接从 JsonSerializer 生成一个新的 class 对象。例如:

Dim jsonPath = "d:\test.json"

' Passing True to the Constuctor, calls the Build() method
Dim serTest = New SerializationTest(True)
' Serialize all property values to the specified File
serTest.Serialize(jsonPath)

' Creates a new SerializationTest objects and fills it
' deserializing the JSON previously saved calling Serialize() 
Dim serTest2 = New SerializationTest(False).Deserialize(jsonPath)

您可以比较两个对象,serTestserTest2
如果需要副本,请参阅底部。

修改class:

Public Class SerializationTest
    Private Shared rnd As New Random()

    Public Sub New()
        Me.New(False)
    End Sub

    Public Sub New(useBuilder As Boolean)
        If useBuilder Then Build()
    End Sub

    Public Property DblArray As Double(,)
    Public Property DblVector As Double()
    Public Property StringVector As String()
    Public Property IntVector As Integer()

    Public Sub Serialize(jsonPath As String)
        Using stream As New StreamWriter(jsonPath)
            Dim jWriter As New JsonTextWriter(stream)
            Dim serializer As New JsonSerializer()
            serializer.Serialize(jWriter, Me)
            jWriter.Close()
        End Using
    End Sub

    Public Function Deserialize(jsonPath As String) As SerializationTest
        Using reader As New StreamReader(jsonPath, Encoding.UTF8)
            Dim jReader As New JsonTextReader(reader) With {
                .FloatParseHandling = FloatParseHandling.Double
            }
            Dim serializer As New JsonSerializer()
            Dim deserialized = serializer.Deserialize(Of SerializationTest)(jReader)
            jReader.Close()
            Return deserialized
        End Using
    End Function

    Private Sub Build()
        ReDim DblArray(1000, 1000)
        ReDim DblVector(1000)
        ReDim StringVector(1000)
        ReDim IntVector(1000)
        For i = 0 To 1000
            DblVector(i) = rnd.NextDouble()
            StringVector(i) = $"A{i}"
            IntVector(i) = rnd.Next(1, 101)
            For j = 0 To 1000
                DblArray(i, j) = rnd.NextDouble()
            Next
        Next
    End Sub
End Class

如果您出于某种原因想要将反序列化的值复制到已初始化但 、class 对象,则更改方法如下:

Public Sub Deserialize(jsonPath As String)
    Using reader As New StreamReader(jsonPath, Encoding.UTF8)
        Dim jReader As New JsonTextReader(reader) With {
            .FloatParseHandling = FloatParseHandling.Double
        }
        Dim serializer As New JsonSerializer()
        Dim deserialized = serializer.Deserialize(Of SerializationTest)(jReader)
        jReader.Close()

        Me.DblArray = deserialized.DblArray
        Me.DblVector = deserialized.DblVector
        Me.StringVector = deserialized.StringVector
        Me.IntVector = deserialized.IntVector
        deserialized = Nothing
    End Using
End Sub

并更改填写的代码:

Dim serTest = New SerializationTest(False)
serTest.Deserialize(jsonPath)