【问题标题】:How to ignore missing nodes when deserialising json in .NET在.NET中反序列化json时如何忽略丢失的节点
【发布时间】:2021-01-19 12:33:54
【问题描述】:

某些 Shopify API 在未配置时不会返回节点,而是返回空值。

JSON 示例

{
  "orders": [
    {
      "id": 1,
      "customer": {
        "id": 001,
      }
    },
    {
      "id": 2
    }
  ]
}

为了反序列化 Json,我需要在类对象中包含所有属性。

Public Class AllOrders
  Public Property orders() As List(Of Order)
End Class

Public Class Order
  Public Property id As Long?
  Public Property customer() As Customer
End Class

Public Class Customer
  Public Property id As Long?
End Class

如何在不复杂的if 语句的情况下有效地跳过丢失的节点。

问题不在于 json 的反序列化,而是试图读取不存在的命名成员。

Dim AllOrders = JsonConvert.DeserializeObject(Of AllOrders)(GetOrders())

For Each order As Shopify.Order In AllOrders.orders
  Dim test as order.customer.id
  'Error NullReferenceException on customer
Next

这可以在 Json.Net 框架内处理吗?


JsonSerializerSettings

我应该注意我已经尝试了以下设置。

Dim settings = New JsonSerializerSettings With {
  .NullValueHandling = NullValueHandling.Ignore,
  .MissingMemberHandling = MissingMemberHandling.Ignore
}

【问题讨论】:

  • DeserializeObject 有一个重载,它采用 JsonSerializerSettings 并且有一个 JsonSerializerSettings.NullValueHandling 属性。 newtonsoft.com/json/help/html/…
  • 您在这里的预期行为是什么?如果节点不存在,那么你想分配什么值?
  • @JohnPete22 在这种情况下,可以接受 Null 或 0。因为我可能不得不对每个属性应用这个检查,所以我试图避免在大约 500 个单独的属性上声明 if 语句。
  • 将客户设置为<JsonProperty("customer", NullValueHandling:=NullValueHandling.Include)> Public Property Customer As Customer = New Customer 怎么样?无论如何,它将创建Customer 对象,并且其Id 属性将设置为0 的默认值(以防0 的值不是可能的值,否则它会产生误导并且处理空值是一种方式更好)

标签: json vb.net json.net deserialization shopify


【解决方案1】:

有几种客户端替代方案可以在一行中处理此问题。

您可以使用空条件运算符?.,如

Dim oneId = order.Customer?.Id

在这种情况下,结果是一个可以为空的Long,但Id 已经是一个可以为空的长整数,因此它不应该改变后续处理,因为您已经需要考虑它可能为空的可能性。如果缺失值只有一个“合理”值,则可以使用GetValueOrDefault 获得保证值。

您可以使用If 运算符的空合并形式,如

Dim guaranteedCustomer = If(order.Customer, defaultCustomer)

这需要一些谨慎,因为使用单个可变对象作为默认值可能会导致以后当其中一个默认值发生突变从而更改所有默认项时出现令人讨厌的错误。

【讨论】:

  • 很好的答案,谢谢。我确实最终得出了 MySelf 的一些结论。虽然我不知道你可以在类上使用空条件运算符。
  • @DreamTeK 我不确定你在课堂上使用它们是什么意思。看起来它始终是您显示的代码中的成员访问权限。但是,我确实错过了一些被标识为数组的东西,对于那些,我认为没有办法对数组进行空条件项访问。
  • 我选择了 GetValueOrDefault。似乎运作良好。
【解决方案2】:

更新以减少一些废话

Public Class AllOrders
    Public Property orders() As List(Of TestOrder)
End Class

Public Class TestOrder

    Public Property id As Long
    Public Property customer As TestCustomer

    Sub New()
        _customer = New TestCustomer()
    End Sub
End Class

Public Class TestCustomer
    Public Property id As Long
End Class


Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    Dim testString As String = <![CDATA[
        {
          "orders": [
            {
              "id": 1,
              "customer": {
                "id": 59,
              }
            },
            {
              "id": 2
            }
          ]
        }
    ]]>.Value
    Dim settings = New JsonSerializerSettings With {.NullValueHandling = NullValueHandling.Include, .MissingMemberHandling = MissingMemberHandling.Ignore}
    Dim all As AllOrders = JsonConvert.DeserializeObject(Of AllOrders)(testString, settings)

    For Each order As TestOrder In all.orders
        Dim test As Long = order.customer.id
        ' ouput is 59 and then 0 for the missing node (integer default value)
    Next
End Sub

【讨论】:

  • 感谢您付出的努力,非常感谢,但我正在寻找一个不那么冗长的解决方案。
  • @DreamTeK 是的,在看到您拥有 500 多个属性后,我对我的帖子进行了编辑。
猜你喜欢
  • 2015-09-04
  • 2014-01-24
  • 2014-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多