F#中带有json.net的反序列化问题 [英] deserialization issue, with json.net, in F#

查看:96
本文介绍了F#中带有json.net的反序列化问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的对象要反序列化,但是我不明白我得到的错误.

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 match PreviousDeposited.
  • "prevWithdrawn" does not match PreviousWithdrawn.
  • 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一起打开问题,要求他们改进DiscriminatedUnionConverteroption字段的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆