I want to extend Newtonsoft.Json.Linq.JObject
Class in order to obtain fast access (in form of properties) to some expressions made on-the-fly from JObject's contents. Let us call the extended class JRecord
.
I also need that JObject
instances can be easily cast to and from the extended type JRecord
. The question is: how I take a JObject
instance and cast it as my extended type (which also inherits from JObject
), in a way it keeps all its content but gets "dressed" with the extra properties when narrowing from JObject
to JRecord
and "striped" of those properties when widening from JRecord
back to JObject
?
Below is my first scratch and I omitted most of the properties because its string building is complex and irrelevant to the problem, which raises on both custom CType()
operators, where .NET tells me that
So, what should I do? Should I create a bare new instance and create children with the same content from those of the object I want to cast?
Public Class JRecord
Inherits JObject
Public Sub New()
MyClass.New
End Sub
Public ReadOnly Property Id As Integer
Get
Return MyBase.Value(Of Integer)("id")
End Get
End Property
Public ReadOnly Property NomeSigla As String
Get
Return String.Format(
"{0} ({1})",
MyBase.Value(Of String)("nome"),
MyBase.Value(Of String)("sigla"))
End Get
End Property
Public Overloads Shared Narrowing Operator CType(json_object As JObject) As JRecord
Return DirectCast(json_object, JRecord)
End Operator
Public Overloads Shared Widening Operator CType(json_record As JRecord) As JObject
Return json_record
End Operator
End Class
I would not use inheritance and conversion operators in this case. Instead, I would use composition here. In other words, make the JRecord
class wrap the original JObject
and delegate to it as needed. To convert from a JObject
to a JRecord
, make the constructor of the JRecord
accept a JObject
. To go the other way, just make a JObject
property on JRecord
and have it return the inner JObject
directly.
Public Class JRecord
Private innerJObject As JObject
Public Sub New(jObject As JObject)
innerJObject = jObject
End Sub
Public ReadOnly Property JObject As JObject
Get
Return innerJObject
End Get
End Property
Public ReadOnly Property Id As Integer
Get
Return innerJObject.Value(Of Integer)("id")
End Get
End Property
Public ReadOnly Property NomeSigla As String
Get
Return String.Format(
"{0} ({1})",
innerJObject.Value(Of String)("nome"),
innerJObject.Value(Of String)("sigla"))
End Get
End Property
End Class
Then you can do things like this:
Dim jr as JRecord = new JRecord(JObject.Parse(jsonString))
Dim id as Integer = jr.Id
Dim ns as String = jr.NomeSigla
Dim jo as JObject = jr.JObject
...
If you absolutely must use inheritance, because you want to pass the JRecord
directly to other places in the application that expect only a JObject
, you could do this:
Public Class JRecord
Inherits JObject
Public Sub New(jObject As JObject)
MyBase.New(jObject)
End Sub
Public ReadOnly Property JObject As JObject
Get
Return Me
End Get
End Property
Public ReadOnly Property Id As Integer
Get
Return Value(Of Integer)("id")
End Get
End Property
Public ReadOnly Property NomeSigla As String
Get
Return String.Format(
"{0} ({1})",
Value(Of String)("nome"),
Value(Of String)("sigla"))
End Get
End Property
End Class
This is nearly the same thing, except now the JRecord
is a JObject
so you can pass it around freely. The tradeoff is that now it has to copy all the properties when the JRecord
is first constructed. We take advantage of JObject
's built-in copy constructor to do this.