【问题标题】:How to handle null values using DeserializeObject method如何使用 DeserializeObject 方法处理空值
【发布时间】:2020-06-22 16:30:59
【问题描述】:

我正在使用 Newtonsoft.Json 反序列化一个对象。我得到以下异常:

Newtonsoft.Json.JsonSerializationException
  HResult=0x80131500
  Message=Error converting value {null} to type 'System.DateTime'. Path 'StartDate', line 1, position 62.
  Source=Newtonsoft.Json
  
Inner Exception 1:
InvalidCastException: Null object cannot be converted to a value type.

原来的json有空值:

{
  "StartDate": null,
  "EndDate": null
}

但我正在向 JsonConvert.DeserializeObject 提供设置以避免空值,如 herehere 所述:

var convertedMessage = JsonConvert.DeserializeObject<T>(
                Encoding.UTF8.GetString(message.Body),
                new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

知道为什么它一直抛出这个异常吗?

如果提供了实际的日期值,则代码运行良好。

有关代码的更多背景信息,message.Body 是通过服务总线(Microsoft.Azure.ServiceBus.Message 类)接收的消息的主体。并对其应用 GetString 方法返回与发送的消息中相同的字符串。

一个可运行的代码示例:

using System;
using System.Text;
using Microsoft.Azure.ServiceBus;
using Newtonsoft.Json;


namespace ConsoleApp1
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine(DeserializeJsonMessage<SampleMessage>(
                new Message(Encoding.UTF8.GetBytes("{\"Id\":\"d2725a22-fdfb-48df-8871-54bbcb1a95b4\",\"StartDate\":null,\"EndDate\":null}"))
                ));
        }

        public static T DeserializeJsonMessage<T>(Message message) where T : IMessage
        {
            var convertedMessage = JsonConvert.DeserializeObject<T>(
                Encoding.UTF8.GetString(message.Body),
                new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

            return convertedMessage;
        }
    }

    public interface IMessage
    {
        Guid Id { get; set; }
        DateTime StartDate { get; set; }
        DateTime EndDate { get; set; }
    }

    public class SampleMessage : IMessage
    {
        public Guid Id { get; set; }
        public DateTime StartDate { get; set; }
        public DateTime EndDate { get; set; }

        public SampleMessage(Guid id, DateTime startDate, DateTime endDate)
        {
            Id = id;
            StartDate = startDate;
            EndDate = endDate;
        }

        public override string ToString()
        {
            return JsonConvert.SerializeObject(this);
        }
    }
}

【问题讨论】:

    标签: c# json.net azureservicebus


    【解决方案1】:

    您是否尝试将开始/结束日期设置为可空对象并由它们实现接口?

    public class SampleMessage : IMessage
    {
        public Guid Id { get; set; }
        public DateTime? StartDate { get; set; }
        public DateTime? EndDate { get; set; }
    
        public SampleMessage(Guid id, DateTime? startDate, DateTime? endDate)
        {
            Id = id;
            StartDate = startDate;
            EndDate = endDate;
        }
    
        public override string ToString()
        {
            return JsonConvert.SerializeObject(this);
        }
    
        DateTime IMessage.StartDate { get => this.StartDate ?? DateTime.Now; set => this.StartDate = value; }
        DateTime IMessage.EndDate { get => this.EndDate ?? DateTime.Now; set => this.EndDate = value; }
    }
    

    【讨论】:

    • 之前试过了,代码抛出了同样的异常。
    • 我错过了构造函数 - 现在应该可以工作了(适用于你的示例)
    • 不错!谢谢。我忘记了我还需要更新构造函数。但是,为什么 JsonSerializer 设置(NullValueHandling.Ignore)不起作用?
    • 我建议使用default(DateTime) 来表示未初始化的值,而不是DateTime.Now
    • @Endovelicvs - 似乎NullValueHandling.Ignore 不适用于构造函数参数,因为构造函数参数的值需要 来构造和反序列化对象。将构造函数参数声明为可为空的可以解决问题。或者你可以使用可以为空的参数创建一个私有构造函数并用[JsonConstructor] 标记它。
    猜你喜欢
    • 2013-07-30
    • 2018-11-22
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多