问题
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 forMyObject
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
(thedocument
variable in the code sample above).
Demo fiddle here.
来源:https://stackoverflow.com/questions/56308478/pass-constructor-arguments-when-deserializing-into-a-listof-t