设置默认值以在反序列化 JSON 时处理丢失的属性

huangapple go评论87阅读模式
英文:

Set default value when deserializing JSON missing properties

问题

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

这是我用于反序列化JSON的类:

Public Class cls_horarios
    ' ... 你的类定义
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ão",
      "expediente_feriados": "0",
      "expediente_bloqueio_pc": 0,
      "expediente_bloqueio_tolerancia": "0"
    }]
  }
}

在这种情况下,我正在尝试分配一个默认值,以便在JSON中没有这些属性时设置默认值,只需删除JSON中标识的行。

这是我用于读取JSON的代码:

Public Sub PreencheConfiguracoesColaborador(ByVal dados As String)
    ' ... 你的代码
End Sub

我已经尝试了在SO上提出的一些解决方案,但都没有成功。我需要在JSON属性缺失时设置默认值,所以我请求大家的帮助来解决这个问题。

英文:

I'm trying to assign a Default value to my class, when I don't have the property listed in the JSON.

This is the class I'm using to deserialize 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

This is the JSON I am trying to deserialize:

{
  "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"
    }],
     }
}

In this scenario, what I'm trying to do is assign a default value so that it doesn't have the properties in the JSON, the default value is set, so that it can be tested, just remove the line that is identified in the JSON

and this is the code I'm using to read the 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

I have already tried the following proposed solutions right here on SO:

https://stackoverflow.com/questions/29611445/default-value-for-missing-properties-with-json-net

https://stackoverflow.com/questions/15452450/why-when-i-deserialize-with-json-net-ignores-my-default-value

But all without success.

What I need is to set the default value when the JSON properties are missing, so I ask for everyone's help to resolve this issue.

答案1

得分: 0

以下是翻译好的部分:

  1. 在JSON中没有为属性"expediente_opcao_quinta"提供值,因此Expediente.expediente_opcao_quintanull

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

  3. 也有缺少字符串值属性,其值默认为null

解决这些问题的最简单方法是在构造时自动将属性初始化为非null值,如Initializing an Auto-Implemented Property中所示,并对任何永远不应为null的属性应用<JsonProperty(NullValueHandling := NullValueHandling.Ignore)>以强制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,看起来对应于一周中的每一天。我猜您使用了某种代码生成工具创建了这些类。代码生成工具有时会无法检测并合并相同的类型,但在这种情况下,它们似乎应该是相同的,因此在我的答案中我将它们设为相同。

  • 在您的问题中,您捕获并忽略所有异常。这通常是一个不好的做法,因为您会丢失有关问题原因的所有信息,而且您的代码可能会继续使用损坏的数据前进。有关更多讨论,请参阅Is catching general exceptions really a bad thing?

  • 尽管您可以使用来自https://stackoverflow.com/q/29611445/3744182的答案来使用DefaultValueAttribute为具有原始值的缺少属性提供默认值,但由于CLR内置了对属性参数类型的限制,因此无法使用DefaultValueAttributeExpedienteOpcao等复杂属性值提供默认值。

演示示例位于此处

英文:

You have a few problems here:

  1. There is no value for the property &quot;expediente_opcao_quinta&quot; in the JSON, thus Expediente.expediente_opcao_quinta is null.

  2. There are several string whose values in the JSON is explicitly null, e.g. &quot;result[0].expediente.expediente_opcao_sabado&quot;.

  3. There are also missing string-valued properties whose values default to null.

The easiest way to resolve these problems is to automatically initialize your properties to non-null values when constructed as shown in Initializing an Auto-Implemented Property, and apply &lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; to any property that should never be null to force Json.NET to ignore null values when deserializing and serializing.

Thus your data model should look like:

Public Class Expediente
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property expediente_opcao_domingo As ExpedienteOpcao = New ExpedienteOpcao()
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property expediente_opcao_segunda As ExpedienteOpcao = New ExpedienteOpcao()
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property expediente_opcao_terca As ExpedienteOpcao = New ExpedienteOpcao()
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property expediente_opcao_quarta As ExpedienteOpcao = New ExpedienteOpcao()
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property expediente_opcao_quinta As ExpedienteOpcao = New ExpedienteOpcao()
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property expediente_opcao_sexta As ExpedienteOpcao = New ExpedienteOpcao()
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
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
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property hora_inicial As String = &quot;&quot;
&lt;JsonProperty(NullValueHandling := NullValueHandling.Ignore)&gt; _
Public Property hora_final As String = &quot;&quot;
End Class
Public Class Result
Public Property expediente As List(Of Expediente)
End Class
Public Class Root
Public Property result As Result
End Class

Notes:

  • You have a seven of identical classes with names like ExpedienteOpcaoDomingo and ExpedienteOpcaoQuarta that seem to correspond to days of the week. I am guessing you created these classes with some code generation tool. Code generation tools will sometimes fail to detect and combine identical types, but since in this case it seems they should be identical, I made them such in my answer.

  • In your question you catch and ignore all exceptions. This is generally a bad idea as you lose all information about the cause of the problem, and your code may proceed forward using corrupt data. See e.g. Is catching general exceptions really a bad thing? for some additional discussion.

  • While you could use the answers from https://stackoverflow.com/q/29611445/3744182 to use DefaultValueAttribute to provide default values for missing properties with primitive values, you cannot use DefaultValueAttribute to provide a default value for a complex property value such as ExpedienteOpcao due to limitations on attribute parameter types built into the CLR.

Demo fiddle here.

huangapple
  • 本文由 发表于 2023年7月28日 01:26:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76782154.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定