我正在使用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)
答案 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字符串值可以解析为long
和DateTime
,但这可以说是Json.NET中的一个错误。
您有几个解决方法:
通过设置JsonSerializerSettings.DateParseHandling = DateParseHandling.None
:
var dateFormatSettings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None,
DateFormatString = "yyyyMMdd"
};
尽管禁用了低级自动识别功能,但明确键入DateTime
的成员仍会正确反序列化。
使用IsoDateTimeConverter { DateTimeFormat = "yyyyMMdd" }
而非设置JsonSerializerSettings.DateFormatString
。
var dateFormatSettings = new JsonSerializerSettings
{
Converters = { new IsoDateTimeConverter { DateTimeFormat = "yyyyMMdd" } }
};
明确键入为DateTime
的成员将使用您想要的格式字符串进行反序列化,同时保留用于低级自动识别的模式不变。
示例fiddle重现问题并演示两个解决方法。