"来自' DateTime'的无效演员表到' Int64'。在反序列化JSON字符串时

时间:2016-12-29 20:33:26

标签: c# json.net

我正在使用C#中的JSON元素解析大型数据文件。对于某些字符串,反序列化失败,错误如下。

 Exception  = Invalid cast from 'DateTime' to 'Int64'.
 Message    = Error converting value 3/28/2172 12:00:00 AM to type 'System.Int64'.  Path 'ProductDetail.productId', line 1, position 4003."

所有字符串都没有出现错误,但似乎暗示该值被解释为DateTime值;但是,它在相关联的类中被定义为 long

我可以强制将值解释为吗?

ProductDetail.productId被定义为以下类型的成员:

   public class ProductDetail
    {
        public string accreditedInvestorInd { get; set; }
        public string accrueAcreteInd { get; set; }
        public DateTime issueDate { get; set; }
        // ... truncated for simplicity

        public long productId { get; set; }

       // ... truncated for simplicity
        public string wkndHolPayInd { get; set; }
        public string zeroCouponInd { get; set; }
    }

我尝试使用转换器属性未能成功,希望强制使用不同的解释。 (不确定我是否正确使用它)......

    [JsonConverter(typeof(string))]
    public long productId { get; set; }

另外,我使用的是自定义DateTime格式。

以下是我尝试反序列化的大数据文件的子集,与ProductDetail对应:

{"accrueAcreteInd":"Y","callableInd":"Y","calledInd":"N","cpnCurrency":"USD","cpnPmtFreqCode":"S","cpnRate":"2.8","curAmtOutstanding":"7825000.0","currencyCode":"USD","cusip":"3130H0AX1","datedDate":"20160303","dayCountMonthCode":"30","dayCountYearCode":"360","daysToSettle":"1","dtcEligibleInd":"Y","eomPmtInd":"N","exchange":"TRACE","fatcaCode":"1","firstCpnPmtDate":"20160901","hqlaCode":"2A","identifier":"3130H0AX1","identifierType":"cusip","inDefaultInd":"N","infoSourceCode":"R21RB","intAccrued":".91777778","intTypeCode":"FIX","is144aInd":"N","issueCountry":"US","issueDate":"20160303","issuePrice":"100.0","issuerIndustryCode":"11","issuerName":"FARMER MAC","issuerTicker":"FAMCA","lastCpnPmtDate":"20250901","lastUpdateTime":"20160830","lastUpdateTimeExt":"00:06:58","longDesc":"FAMCA 2.8 03/01/2026","maturityDate":"20260301","minDenom":"1000.0","minParAmount":"1000.0","mktSectorDes":"Govt","mtnInd":"Y","nextCallDate":"20170301","nextCallPrice":"100.0","nextCpnPmtDate":"20170301","origIssueAmt":"7825000.0","prevCpnPmtDate":"20160901","primaryIssInd":"Y","privatePlacementInd":"N","productId":"21720328","productTypeCode":"FRMNT","putableInd":"N","pxCleanInd":"Y","redempVal":"100.0","regSInd":"N","restrictedInd":"N","secHoldInd":"N","securityType":"FAMCCL","series":"NOTZ","shortDesc":"FAMCA 2.8 03/26","sinkableInd":"N","traceEligibleInd":"N","truePutInd":"N","wkndHolPayInd":"N","zeroCouponInd":"N"}

以下是我尝试反序列化子集的方法,其中Line是上面的JSON字符串:

var dateFormatSettings = new JsonSerializerSettings { DateFormatString = "yyyyMMdd" };
var detail = JsonConvert.DeserializeObject<ProductDetail>(Line, dateFormatSettings);

以下是简化JSON的完整例外:

Newtonsoft.Json.JsonSerializationException: Error converting value 3/28/2172 12:00:00 AM to type 'System.Int64'. Path 'productId', line 1, position 1117. ---> System.InvalidCastException: Invalid cast from 'DateTime' to 'Int64'.
   at System.DateTime.System.IConvertible.ToInt64(IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   --- End of inner exception stack trace ---
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue(JsonProperty property, JsonConverter propertyConverter, JsonContainerContract containerContract, JsonProperty containerProperty, JsonReader reader, Object target)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)

1 个答案:

答案 0 :(得分:0)

问题与您正在使用的具体DateFormatString有关:

var dateFormatSettings = new JsonSerializerSettings { DateFormatString = "yyyyMMdd" };

JSON没有literal syntax for dates因此,在较低级别,Json.NET使用DateFormatString设置进​​行一些模式匹配以识别日期字符串。很遗憾,DateFormatString yyyyMMdd设置与以下两种JSON属性匹配:

   "issueDate":"20160303", // Should deserialize to a DateTime
   "productId":"21720328", // Should deserialize to a long

因此,当第一个被正确识别为日期时,第二个也是,最终导致更高代码级别的"Invalid cast from 'DateTime' to 'Int64'."异常。它是一个边缘案例,因为对应于long成员的JSON字符串值可以解析为longDateTime,但这可以说是Json.NET中的一个错误。

您有几个解决方法:

  1. 通过设置JsonSerializerSettings.DateParseHandling = DateParseHandling.None

    禁用自动日期识别
    var dateFormatSettings = new JsonSerializerSettings
    {
        DateParseHandling = DateParseHandling.None,
        DateFormatString = "yyyyMMdd"
    };
    

    尽管禁用了低级自动识别功能,但明确键入DateTime的成员仍会正确反序列化。

  2. 使用IsoDateTimeConverter { DateTimeFormat = "yyyyMMdd" }而非设置JsonSerializerSettings.DateFormatString

    var dateFormatSettings = new JsonSerializerSettings
    {
        Converters = { new IsoDateTimeConverter { DateTimeFormat = "yyyyMMdd" } }
    };
    

    明确键入为DateTime的成员将使用您想要的格式字符串进行反序列化,同时保留用于低级自动识别的模式不变。

  3. 示例fiddle重现问题并演示两个解决方法。