f# - F# 中的 json.net 反序列化问题
问题描述
我有一个要反序列化的简单对象,但我不明白我得到的错误。
代码如下:
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.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter 转换器,JsonReader Reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType) at ...
我不明白是什么让“TransferOut”属性如此特别,以至于它停在这个上,而不是之前的任何其他相同的上。
我在这里有一个小提琴:https ://dotnetfiddle.net/HGiia5
解决方案
你在这里有几个问题。
首先,您用于option
字段的 JSON 语法与 Json.NET 的语法不匹配。如果我们将您的类型简化如下:
type r =
{
TransferIn: int64 option
TransferOut: int64 option
}
并序列化一个实例如下:
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在这里。
"transferIn": 1000000
您用于option
字段的简单语法不是由DiscriminatedUnionConverter
Json.NET 用于序列化包括可选字段的可区分联合的转换器实现的。这种不匹配导致读取 JSON 时出现异常。
相关地,请参阅序列化 F# 选项类型,其中建议使用 nuget 包,该包提供支持此简化语法的JsonConverter
for 。option<_>
其次,许多 JSON 属性名称与您的 f# 记录名称不匹配。Json.NET 使用不区分大小写的算法将 JSON 属性名称与 f# 构造函数参数和成员名称匹配,但您的许多 JSON 名称不匹配:
"prevDeposited"
不匹配PreviousDeposited
。"prevWithdrawn"
不匹配PreviousWithdrawn
。- 还有其他几个。
事实上,JSON 中第一个真正匹配option
字段的属性是"transferIn"
. 您收到一个错误,"transferOut"
因为它紧跟"transferIn"
未成功反序列化的值。
最后,当字段没有出现在 JSON 对象的末尾时,Json.NET 为option
字段的无效 JSON 值抛出的错误消息是无用的。如果我将输入 JSON 简化如下:
{
"transferIn": 1000000,
}
我们得到一个更有用的错误信息
Newtonsoft.Json.JsonSerializationException:找不到具有联合名称的“案例”属性。路径'',第 3 行,位置 1。
演示小提琴#2在这里。
但是,当"transferIn"
后面跟着另一个 JSON 键/值对时,错误消息会变成您的问题中显示的不太有用的消息。您可能会向Newtonsoft 提出问题DiscriminatedUnionConverter
,要求他们改进当字段的 JSON 值option
与预期架构不匹配并且包含对象中存在后续 JSON 属性时引发的错误消息。
推荐阅读
- tensorflow - 如何在服务器中分别发送视频数据和对象检测边界框,然后一起播放
- python - 如何在现有的 xml 文件中添加命名空间
- html - 如何使用角材料的扩展面板打开多面板?
- android - 在方向改变时恢复 Lottie 动画
- http - 如何使用 Kubernetes Nginx 入口控制器禁用对服务的 http 访问?
- vba - 使用 Microsoft Word 生成 Code 128 条码
- sql - 如何在oracle中插入0001年?
- python - Amazon sp_api - 使用受限数据令牌获取订单地址
- pyspark - ValueError:无法将字符串转换为浮点数:'"r_version"' - 将温度转换为华氏温度时
- ansible - 在列表中循环列表