Pass constructor arguments when deserializing into a List(Of T)

佐手、 提交于 2019-12-24 09:06:48

问题


I need to serialize and deserialize a List(of T) via JSON.Net, where T is an object which contains a reference which cannot be serialized. Here is a simplified version:

Class MyObject

    Private ReadOnly _Parent As Word.Document

    Property Foo As String
    Property Bar As String

    Sub New(Parent As Word.Document, Foo As String, Bar As String)
        Me.New(Parent)
        Me.Foo = Foo
        Me.Bar = Bar
    End Sub

    Sub New(Parent As Word.Document)
        _Parent = Parent
    End Sub

    <JsonConstructor>
    Private Sub New()
    End Sub

    Function GetFile() As System.IO.FileInfo
        Return New FileInfo(_Parent.FullName)
    End Function

End Class

For the story, I store the JSON string (serialized list) inside a Word document variable. When I open the document, I take the string, deserialize it, and then I would like to be able to set the _Parent field to refer to the same document. The difficulty is not in knowing what _Parent should reference to, but to set the reference. Note I want to keep it Private, however it could be read/write if necessary.

Is there a way to tell JSON.Net to use the New(Parent As Word.Document) constructor, and to pass this Parent argument via JsonConvert.DeserializeObject(Of T)? Or at least to tell JSON.Net I want to run a specific Sub before/after deserializing?

An easy bypass is be to have the constructor below, but I dot not like it as it may get messed up if several documents are opened at the same time.

<JsonConstructor>
Private Sub New()
    _Parent = ThisWordApp.ActiveDocument
End Sub

I'm fine with responses in C#.


回答1:


You could adopt the second approach from this answer to Pass additional data to JsonConverter and create a CustomCreationConverter(Of MyObject) that allocates an instance of MyObject using a Word.Document passed into the converter itself.

First, define the following converter:

Class MyObjectConverter
    Inherits CustomCreationConverter(Of MyObject)

    Private ReadOnly _Parent As Word.Document           

    Sub New(Parent As Word.Document)
        If Parent Is Nothing Then
            Throw New ArgumentNullException("Parent")
        End If
        _Parent = Parent
    End Sub

    Overrides Function Create(objectType as Type) As MyObject
        Return New MyObject(_Parent)
    End Function
End Class

Then you can use it as follows:

Dim settings = New JsonSerializerSettings() With { .Converters = { new MyObjectConverter(document) } }
Dim list = JsonConvert.DeserializeObject(Of List(Of MyObject))(jsonString, settings)

Notes:

  • This solution has the added advantage that you no longer need the <JsonConstructor> Private Sub New() constructor for MyObject and can completely remove it.

  • This converter would never be applied at compile time using JsonConverterAttribute, it should only be constructed in runtime given a known Word.Document (the document variable in the code sample above).

Demo fiddle here.



来源:https://stackoverflow.com/questions/56308478/pass-constructor-arguments-when-deserializing-into-a-listof-t

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!