F#中带有json.net的反序列化问题 [英] deserialization issue, with json.net, in F#
问题描述
我有一个简单的对象要反序列化,但是我不明白我得到的错误.
I have a simple object to deserialize, but I do not understand the error I get.
代码如下:
open System
open Newtonsoft.Json
type r =
{
Timestamp: DateTime
Currency: string
PreviousDeposited: int64 option
PreviousWithdrawn: int64 option
PreviousTransferIn: int64 option
PreviousTransferOut: int64 option
PreviousAmount: int64 option
TransferIn: int64 option
TransferOut: int64 option
Amount: int64 option
PendingCredit: int64 option
PendingDebit: int64 option
ConfirmedDebit: int64 option
}
let a =
"{
\"account\": 117122,
\"currency\": \"XBt\",
\"prevDeposited\": 747841316,
\"prevWithdrawn\": 2160000,
\"prevTransferIn\": 1000000,
\"prevTransferOut\": 0,
\"prevAmount\": 656893723,
\"prevTimestamp\": \"2020-06-13T12:00:00.005Z\",
\"deltaDeposited\": 0,
\"deltaWithdrawn\": 0,
\"deltaTransferIn\": 0,
\"deltaTransferOut\": 0,
\"deltaAmount\": 0,
\"deposited\": 747841316,
\"withdrawn\": 2160000,
\"transferIn\": 1000000,
\"transferOut\": 0,
\"amount\": 656893723,
\"pendingCredit\": 0,
\"pendingDebit\": 0,
\"confirmedDebit\": 0,
\"timestamp\": \"2020-06-13T12:00:00.643Z\",
\"addr\": \"2NBMEXRW4oCiNzVUq4uVFRSsK2jtTLbtfc7\",
\"script\": \"532102c10be2f0dc20f4285c25156aa22a0c46d2b89ccc4d1c8eaed92ea0c1a8f40c002102ceba29da1af96a0f2ef7cda6950b8be2baeb1adf12c0d5efebb70dbcaa086ba021034ab762f4ede40311e9f8bf01db0bbea578497ac6ccc8aa94a74394b05a53d94b2103d5a42b90e9d7156155661979530a09d2e12e252ef4104e5611274a7ae7e2b09454ae\",
\"withdrawalLock\": []
}"
JsonConvert.DeserializeObject<r> a
我得到这个错误:
Newtonsoft.Json.JsonSerializationException:意外的属性 阅读工会时发现"transferOut".路径"transferOut",第18行, 位置18.]在 Newtonsoft.Json.Converters.DiscriminatedUnionConverter.ReadJson(JsonReader 阅读器,类型objectType,对象existValue,JsonSerializer 序列化器) Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter 转换器,JsonReader阅读器,类型objectType,对象existingValue)
在 Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract 合同,JsonProperty containerProperty,JsonReader阅读器,类型 objectType)在 ...
Newtonsoft.Json.JsonSerializationException: Unexpected property 'transferOut' found when reading union. Path 'transferOut', line 18, position 18.] at Newtonsoft.Json.Converters.DiscriminatedUnionConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer) at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType) at ...
我不明白是什么使属性'TransferOut'如此特殊,以至于它停在了这个位置上,而不是之前的任何其他相同位置上.
I do not understand what makes the property 'TransferOut' so special that it stops on this one, and not on any of the other identical ones before.
我在这里有一个小提琴: https://dotnetfiddle.net/HGiia5
I have a fiddle here: https://dotnetfiddle.net/HGiia5
推荐答案
您在这里遇到了一些问题.
You have a few problems here.
首先,用于option
字段的JSON语法与Json.NET的语法不匹配.如果我们将您的类型简化如下:
Firstly, the JSON syntax you are using for an option
field does not match Json.NET's syntax. If we simplify your type as follows:
type r =
{
TransferIn: int64 option
TransferOut: int64 option
}
并按如下所示序列化实例:
And serialize an instance as follows:
let item : r = { TransferIn = Some 1000000L; TransferOut = None}
let json = JsonConvert.SerializeObject(item,Formatting.Indented)
printfn "%s" json
let item2 = JsonConvert.DeserializeObject<r> json // No exception
结果是:
{
"TransferIn": {
"Case": "Some",
"Fields": [
1000000
]
},
"TransferOut": null
}
成功往返.演示小提琴#1 此处.
Which round-trips successfully. Demo fiddle #1 here.
用于option
字段的简单语法"transferIn": 1000000
未由 DiscriminatedUnionConverter
,Json.NET用于序列化包含可选字段的已区分联合的转换器.这种不匹配会导致在读取JSON时出现异常.
The simple syntax "transferIn": 1000000
you are using for option
fields is not implemented by DiscriminatedUnionConverter
, the converter that Json.NET uses for serializing discriminated unions including optional fields. This mismatch is causing an exception while reading the JSON.
相关信息,请参见 序列化F#选项类型 ,其中建议使用nuget程序包提供了 JsonConverter
支持这种简化语法的option<_>
.
Relatedly, see Serializing F# Option types which has a suggestion for a nuget package that provides a JsonConverter
for option<_>
that supports this simplified syntax.
其次,许多JSON属性名称与您的f#记录名称不匹配. Json.NET使用不区分大小写的算法来将JSON属性名称与f#构造函数参数和成员名称匹配,但是您的许多JSON名称不匹配:
Secondly, many of the JSON property names do not match your f# record names. Json.NET uses an ordinal-case-insensitive algorithm to match JSON property names to f# constructor arguments and member names, but many of your JSON names do not match:
-
"prevDeposited"
与PreviousDeposited
不匹配. -
"prevWithdrawn"
与PreviousWithdrawn
不匹配. - 还有其他几个人.
"prevDeposited"
does not matchPreviousDeposited
."prevWithdrawn"
does not matchPreviousWithdrawn
.- And several others.
实际上,JSON中与option
字段实际匹配的第一个属性是"transferIn"
.您收到有关"transferOut"
的错误,因为它会紧随未成功反序列化的"transferIn"
的值.
In fact the first property in the JSON that actually matches an option
field is "transferIn"
. You are receiving an error about "transferOut"
because it immediately follows the value of "transferIn"
which was not deserialized successfully.
最后,当字段没有出现在JSON对象的末尾时,Json.NET为option
字段的无效JSON值抛出的错误消息是无用的 .如果我将输入JSON简化如下:
Finally, the error message that Json.NET is throwing for invalid JSON values for option
fields is non-useful when the field does not appear at the end of a JSON object. If I simplify the input JSON as follows:
{
"transferIn": 1000000,
}
我们收到了一条更有用的错误消息
The we get a much more useful error message
Newtonsoft.Json.JsonSerializationException:找不到带有联合名称的'Case'属性.路径",第3行,位置1.
Newtonsoft.Json.JsonSerializationException: No 'Case' property with union name found. Path '', line 3, position 1.
演示小提琴#2 此处.
但是,当"transferIn"
后跟另一个JSON键/值对时,错误消息将成为问题中显示的不太有用的消息.您可能会与Newtonsoft一起打开问题,要求他们改进DiscriminatedUnionConverter
当option
字段的JSON值与期望的模式不匹配,并且包含的对象中包含后续的JSON属性时,抛出该异常.
But when "transferIn"
is followed by another JSON key/value pair the error message becomes the less useful message shown in your question. You might open an issue with Newtonsoft asking them to improve the error message that DiscriminatedUnionConverter
throws when the JSON value for an option
field does not match the expected schema and there are subsequent JSON properties in the containing object.
这篇关于F#中带有json.net的反序列化问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!