You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Newtonsoft反序列化含只读属性对象的最佳实践是什么?

使用Newtonsoft反序列化含公共只读属性的对象

我遇到了Newtonsoft反序列化的问题:默认情况下它需要非只读公共属性,但我希望仅使用公共只读属性。

我的简化类gridTradingState如下:

Class gridTradingState
    ReadOnly Property bidInBase As Decimal
    ReadOnly Property askInBase As Decimal
    ReadOnly Property high As Decimal
    ReadOnly Property low As Decimal
    ReadOnly Property dateSinceLastTransactions As Date
    ReadOnly Property suggestedLow As Decimal
    ReadOnly Property suggestedhigh As Decimal
End Class

对应的JSON数据(已修正末尾多余的]}):

{"bidInBase":0.00033485,"askInBase":0.00034407,"highInBase":0.00045,"lowInBase":0.00025797,"dateSinceLastTransactions":"2022-11-21T20:48:00.1243771+07:00","suggestedLow":0.0002,"suggestedhigh":0.0006}

这个类没有默认构造函数,Newtonsoft默认会先调用默认构造函数再设置属性,但只读属性无法被外部修改。目前我是手动解析JSON后调用带参构造函数创建实例:

Protected Sub New(bidInBase As Decimal, askInBase As Decimal, highInBase As Decimal, lowinbase As Decimal, orders As OrderAlreadyPlacedAtanExchange(), dateSinceLastTransactions As Date)
    _bidInBase = bidInBase
    _askInBase = askInBase
    _highInBase = highInBase
    _lowInBase = lowinbase
    _dateSinceLastTransactions = dateSinceLastTransactions
End Sub

Public Shared Function creategridtradingOldStateFromJson(json As String) As gridTradingState
    Dim jo = JToken.Parse(json)
    Dim dateInJson = Convert.ToDateTime(jo.Item("dateSinceLastTransactions").ToString)
    Dim orders As OrderAlreadyPlacedAtanExchange() = Nothing
    Dim output = New gridTradingState(CDec(jo.Item("bidInBase")), CDec(jo.Item("askInBase")), CDec(jo.Item("high")), CDec(jo.Item("low")), orders, dateInJson)
    Return output
End Function

但手动处理不是最优解,请问使用Newtonsoft反序列化这类对象的正确方式是什么?


正确实现方式

针对VB.NET的只读属性,Newtonsoft提供了两种优雅的解决办法,无需手动解析JSON:

方法1:用[JsonConstructor]标记带参构造函数

给类的带参构造函数加上JsonConstructor特性,Newtonsoft会自动匹配JSON字段和构造函数参数(参数名大小写不敏感),直接通过构造函数初始化只读属性。

如果JSON字段名和构造函数参数名不匹配(比如类属性是high但JSON是highInBase),可以用[JsonProperty]明确映射:

Imports Newtonsoft.Json

Class gridTradingState
    ReadOnly Property bidInBase As Decimal
    ReadOnly Property askInBase As Decimal
    ReadOnly Property high As Decimal
    ReadOnly Property low As Decimal
    ReadOnly Property dateSinceLastTransactions As Date
    ReadOnly Property suggestedLow As Decimal
    ReadOnly Property suggestedhigh As Decimal

    <JsonConstructor>
    Protected Sub New(
        bidInBase As Decimal,
        askInBase As Decimal,
        <JsonProperty("highInBase")> high As Decimal,
        <JsonProperty("lowInBase")> low As Decimal,
        dateSinceLastTransactions As Date,
        suggestedLow As Decimal,
        suggestedhigh As Decimal
    )
        Me.bidInBase = bidInBase
        Me.askInBase = askInBase
        Me.high = high
        Me.low = low
        Me.dateSinceLastTransactions = dateSinceLastTransactions
        Me.suggestedLow = suggestedLow
        Me.suggestedhigh = suggestedhigh
    End Sub
End Class

之后直接用常规反序列化方法即可:

Dim state = JsonConvert.DeserializeObject(Of gridTradingState)(json)

方法2:给私有字段加[JsonProperty]映射

如果只读属性基于私有字段实现,可给私有字段加上JsonProperty特性,让Newtonsoft直接序列化/反序列化私有字段,无需修改构造函数:

Imports Newtonsoft.Json

Class gridTradingState
    Private _bidInBase As Decimal
    Private _askInBase As Decimal
    Private _high As Decimal
    Private _low As Decimal
    Private _dateSinceLastTransactions As Date
    Private _suggestedLow As Decimal
    Private _suggestedhigh As Decimal

    <JsonProperty("bidInBase")>
    ReadOnly Property bidInBase As Decimal
        Get
            Return _bidInBase
        End Get
    End Property

    <JsonProperty("askInBase")>
    ReadOnly Property askInBase As Decimal
        Get
            Return _askInBase
        End Get
    End Property

    <JsonProperty("highInBase")>
    ReadOnly Property high As Decimal
        Get
            Return _high
        End Get
    End Property

    <JsonProperty("lowInBase")>
    ReadOnly Property low As Decimal
        Get
            Return _low
        End Get
    End Property

    <JsonProperty("dateSinceLastTransactions")>
    ReadOnly Property dateSinceLastTransactions As Date
        Get
            Return _dateSinceLastTransactions
        End Get
    End Property

    <JsonProperty("suggestedLow")>
    ReadOnly Property suggestedLow As Decimal
        Get
            Return _suggestedLow
        End Get
    End Property

    <JsonProperty("suggestedhigh")>
    ReadOnly Property suggestedhigh As Decimal
        Get
            Return _suggestedhigh
        End Get
    End Property
End Class

同样直接调用标准反序列化方法即可完成对象初始化:

Dim state = JsonConvert.DeserializeObject(Of gridTradingState)(json)

注意事项

  1. 确保JSON格式合法,原JSON末尾的]}属于无效字符,需删除。
  2. 若构造函数包含JSON中未出现的参数(如示例中的orders),需给参数设置默认值,避免反序列化报错。

内容的提问来源于stack exchange,提问作者user4951

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:11:28