在反序列化 JSON 缺少的属性时设置默认值

Set default value when deserializing JSON missing properties

提问人:Luiz 提问时间:7/28/2023 最后编辑:dbcLuiz 更新时间:7/28/2023 访问量:152

问:

当我没有在JSON中列出属性时,我正在尝试为我的类分配默认值。

这是我用来反序列化 JSON 的类

Public Class cls_horarios

   
    Public Class Expediente

        Public Property expediente_opcao_domingo As ExpedienteOpcaoDomingo
        Public Property expediente_opcao_segunda As ExpedienteOpcaoSegunda
        Public Property expediente_opcao_terca As ExpedienteOpcaoTerca
        Public Property expediente_opcao_quarta As ExpedienteOpcaoQuarta
        Public Property expediente_opcao_quinta As ExpedienteOpcaoQuinta
        Public Property expediente_opcao_sexta As ExpedienteOpcaoSexta
        Public Property expediente_opcao_sabado As ExpedienteOpcaoSabado
        Public Property expediente_feriados As String
        Public Property expediente_bloqueio_pc As String
        Public Property expediente_bloqueio_tolerancia As String
    End Class

    Public Class ExpedienteOpcaoDomingo
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoQuarta
     Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoQuinta
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoSegunda
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoSexta
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class

    Public Class ExpedienteOpcaoTerca
        Public Property isDiaUtil As Integer
        Public Property hora_inicial As String
        Public Property hora_final As String
    End Class
   
    Public Class Result
        Public Property expediente As List(Of Expediente)
    End Class

    Public Class Root
        Public Property result As Result
    End Class

这是我尝试反序列化的 JSON:

{
  "result": {
    "expediente": [{
      "expediente_opcao_domingo": {
        "isDiaUtil": 0,
        "hora_inicial": null,
        "hora_final": null
      },
      "expediente_opcao_segunda": {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_terca": {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_quarta":
      {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_sexta": {
        "isDiaUtil": 1,
        "hora_inicial": "09:00",
        "hora_final": "18:48"
      },
      "expediente_opcao_sabado": {
        "isDiaUtil": 0,
        "hora_inicial": null,
        "hora_final": null
      },
      "expediente_nome": "padr\u00e3o",
      "expediente_feriados": "0",
      "expediente_bloqueio_pc": 0,
      "expediente_bloqueio_tolerancia": "0"
    }],
     }
}

在这种情况下,我尝试做的是分配一个默认值,使其在JSON中没有属性,设置默认值,以便可以对其进行测试,只需删除JSON中标识的行即可

这是我用来读取 JSON 的代码

Public Sub PreencheConfiguracoesColaborador(ByVal dados As String)

        '//INICIO EXPEDIENTE DO COLABORADOR


        Dim horarioColab As cls_horarios.Root = JsonConvert.DeserializeObject(Of cls_horarios.Root)(dados)
        expediente_colab_quantidade = 0

        
        Try
            For Each item As Expediente In horarioColab.result.expediente

                expediente_colab_feriado = item.expediente_feriados
                expediente_colab_bloqueio_pc = item.expediente_bloqueio_pc
                expediente_colab_bloqueio_tolerancia = item.expediente_bloqueio_tolerancia

                expediente_colab_domingo = item.expediente_opcao_domingo.isDiaUtil
                expediente_colab_domingo_hora_entrada = FormatDateTime(item.expediente_opcao_domingo.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_domingo_hora_saida = FormatDateTime(item.expediente_opcao_domingo.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_segunda = item.expediente_opcao_segunda.isDiaUtil
                expediente_colab_segunda_hora_entrada = FormatDateTime(item.expediente_opcao_segunda.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_segunda_hora_saida = FormatDateTime(item.expediente_opcao_segunda.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_terca = item.expediente_opcao_terca.isDiaUtil
                expediente_colab_terca_hora_entrada = FormatDateTime(item.expediente_opcao_terca.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_terca_hora_saida = FormatDateTime(item.expediente_opcao_terca.hora_final.ToString, DateFormat.LongTime)


                expediente_colab_quarta = item.expediente_opcao_quarta.isDiaUtil
                expediente_colab_quarta_hora_entrada = FormatDateTime(item.expediente_opcao_quarta.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_quarta_hora_saida = FormatDateTime(item.expediente_opcao_quarta.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_quinta = item.expediente_opcao_quinta.isDiaUtil
                expediente_colab_quinta_hora_entrada = FormatDateTime(item.expediente_opcao_quinta.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_quinta_hora_saida = FormatDateTime(item.expediente_opcao_quinta.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_sexta = item.expediente_opcao_sexta.isDiaUtil
                expediente_colab_sexta_hora_entrada = FormatDateTime(item.expediente_opcao_sexta.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_sexta_hora_saida = FormatDateTime(item.expediente_opcao_sexta.hora_final.ToString, DateFormat.LongTime)

                expediente_colab_sabado = item.expediente_opcao_sabado.isDiaUtil
                expediente_colab_sabado_hora_entrada = FormatDateTime(item.expediente_opcao_sabado.hora_inicial.ToString, DateFormat.LongTime)
                expediente_colab_sabado_hora_saida = FormatDateTime(item.expediente_opcao_sabado.hora_final.ToString, DateFormat.LongTime)


                'expediente_colab_expediente_nome = item.expediente_nome
                expediente_colab_quantidade += 1
                Console.WriteLine("Feriado: " & expediente_colab_feriado & " Bloqueio Pc: " & expediente_colab_bloqueio_pc & " Bloqueio Tolerancia: " & expediente_colab_bloqueio_tolerancia & " Expediente Nome: " & expediente_colab_expediente_nome)

            Next

        Catch ex As Exception
            writeExeption(ex, False)
            Console.WriteLine("Erro Expediente: " & ex.Message)
        End Try

    End Sub

我已经在 SO 上尝试了以下建议的解决方案:

缺少 JSON.net 属性的默认值

为什么当我使用 JSON.NET 反序列化时会忽略我的默认值?

但都没有成功。

我需要的是当缺少JSON属性时设置默认值,因此我请求大家的帮助来解决此问题。

JSON vb.net json.net

评论

0赞 dbc 7/28/2023
请您编辑您的问题并尝试简化一点 - 即分享一个最小的可重复示例?事实上,你有很多代码,但并不完全清楚你在哪里挣扎。
0赞 dbc 7/28/2023
此外,您写道,您尝试了 JSON.net 缺失属性的默认值中的答案,但没有成功。请您编辑您的问题以进行演示吗?我相信添加例如 应在反序列化时给出默认值。<DefaultValue(1)> Public Property isDiaUtil As IntegerisDiaUtil1
0赞 dbc 7/28/2023
最后,为什么不直接在类构造函数中分配默认值呢?是否希望仅在反序列化时设置默认值,而不是在内存中构造时设置默认值?
0赞 Luiz 7/28/2023
@dbc,我试图将我的整个代码用于演示,因为我的类有几个属性,我相信如果我得到我需要的解决方案,就很容易将其应用于其余部分。
0赞 Luiz 7/28/2023
@dbc此解决方案中,<DefaultValue(1)> 公共属性 isDiaUtil As Integer 不会给我默认值,而是给我一个 System.NullReferenceException:“对象引用未设置为对象的实例。 qtservices.cls_horarios。Expediente.expediente_opcao_quinta.get 返回 什么都没有,因为我的 Json 中没有属性expediente_opcao_quinta,我无法设置默认值

答:

0赞 dbc 7/28/2023 #1

您在这里遇到了一些问题:

  1. JSON 中没有该属性的值,因此是 。"expediente_opcao_quinta"Expediente.expediente_opcao_quintanull

  2. 有几个字符串在 JSON 中的值显式为 null,例如 ."result[0].expediente.expediente_opcao_sabado"

  3. 此外,还缺少字符串值属性,其值默认为 。null

解决这些问题的最简单方法是在构造时自动将属性初始化为非 null 值,如初始化自动实现的属性中所示,并将 <JsonProperty(NullValueHandling := NullValueHandling.Ignore)>应用于不应为 null 的任何属性,以强制 Json.NET 在反序列化和序列化时忽略 null 值。

因此,您的数据模型应如下所示:

Public Class Expediente
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_domingo As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_segunda As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_terca As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_quarta As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_quinta As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_sexta As ExpedienteOpcao = New ExpedienteOpcao()
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property expediente_opcao_sabado As ExpedienteOpcao = New ExpedienteOpcao()

    Public Property expediente_feriados As String
    Public Property expediente_bloqueio_pc As String
    Public Property expediente_bloqueio_tolerancia As String
End Class

Public Class ExpedienteOpcao
    Public Property isDiaUtil As Integer
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property hora_inicial As String = ""
    <JsonProperty(NullValueHandling := NullValueHandling.Ignore)> _
    Public Property hora_final As String = ""
End Class

Public Class Result
    Public Property expediente As List(Of Expediente)
End Class

Public Class Root
    Public Property result As Result
End Class

笔记:

  • 你有七个相同的类,名称像 和 似乎对应于一周中的几天。我猜你是用一些代码生成工具创建的这些类的。代码生成工具有时无法检测和组合相同的类型,但由于在这种情况下它们似乎应该是相同的,所以我在回答中将它们设置为相同。ExpedienteOpcaoDomingoExpedienteOpcaoQuarta

  • 在您的问题中,您可以捕获并忽略所有异常。这通常是一个坏主意,因为您丢失了有关问题原因的所有信息,并且您的代码可能会使用损坏的数据继续。例如,参见 捕获一般异常真的是一件坏事吗?

  • 虽然可以使用“缺少属性的默认值”中的答案 JSON.net 用于为具有基元值的缺失属性提供默认值,但不能用于为复杂属性值提供默认值,例如,由于 CLR 中内置的特性参数类型的限制DefaultValueAttributeDefaultValueAttributeExpedienteOpcao

在这里演示小提琴。

评论

0赞 Luiz 7/28/2023
非常感谢您的帮助,它工作得很好......至于生成代码,是的,它是由自动类生成器完成的。我会努力提高我的编码......再次感谢您的帮助.....