F#:如何反序列化带有 Newtonsoft.Json 的私有可区分联合?
F#: How to deserialize a private discriminated union with Newtonsoft.Json?
在 , Onur Gumus 中使用 [] 启用 serialization/deserialization 带有私有构造函数的可区分联合。
对我来说,序列化工作如所宣传的那样,但反序列化会产生此错误:“Newtonsoft.Json.JsonSerializationException:无法找到用于类型 FSI_0037+Foo 的构造函数。A class 应该有一个默认构造函数、一个带参数的构造函数或一个标有 JsonConstructor 属性的构造函数。"
有谁知道如何使反序列化工作?如果可以避免,我不想切换到 class 类型。但是,我已经尝试找出放置 JsonConstructor 属性的位置,但没有任何运气。我还尝试将 a settings value with the ConstructorHandling 值集传递给 AllowNonPublicDefaultConstructor,但没有任何改变。
为方便起见,我将Onur的解决方案复制到这里:
open Newtonsoft.Json
[<JsonObject(MemberSerialization = MemberSerialization.Fields)>]
type Foo = private Bar of string
let f = Bar "f"
let s = JsonConvert.SerializeObject(f)
let f2 = JsonConvert.DeserializeObject<Foo>(s)
printf "%A" f2
以防万一(自 2018 年以来情况似乎发生了变化),我使用的是 .NET 5。
我有理由相信您遇到了错误。
当我将您引用的示例代码复制到 LINQPad v6.13.13 和 运行 时,它运行良好。然后我尝试用另一个属性替换该属性 - 我在评论中提到的那个。不出所料,没有编译。所以我只是恢复到原来的属性。然后我遇到了与您遇到的相同的编译错误。那不应该发生。这是一个错误。但是在哪里?
进一步调查发现,如果我在LINQPad中执行以下操作,则会错误地产生编译错误:
- 从文件中打开代码片段,并尝试 运行 它。这编译并且运行没问题。
- 注释掉属性,并尝试运行它。这会产生有问题的编译错误。这是应该的。
- 带回属性,并尝试 运行 它。这应该可以编译并且 运行 当然可以,因为源代码现在与步骤 1 中的一样,但它仍然会产生有问题的编译错误。
无论我是否在 运行 秒之间重启 LINQPad,重复尝试相同的步骤都会产生同样的问题。
然后我尝试用 Visual Studio 重现问题。我没有成功——在VS 16.10.3
中没有这个问题
暂时没有时间,稍后会继续调查。我想用最新的 LINQPad beta 来检查一下。
至于你的问题,是这个原因吗?
更新
我现在已经检查了 LINQPad v6.14.10,当前的测试版。该错误不存在。我并不感到意外。正如我在评论中提到的,编译器是我的主要嫌疑人。更重要的是,因为你告诉你在 VSCode 中有问题。但还有一个更有趣的细节。
LINQPad 多年来一直使用非常旧版本的 F# 编译器服务,因为存在一个阻止更新它的错误。 LINQPad 的创建者 Joseph Albahari 最近迫不及待地等待修复此错误,并找到了解决方法。该修复程序仅处于测试阶段。 F# 编译器服务版本的巨大飞跃自然意味着许多错误已得到修复,可能还有这个。
我不打算进一步探讨这个问题。我不使用 VSCode,但如果即使在最新的 REPL 中也存在这个问题,那么也许有人应该调查一下。
在
对我来说,序列化工作如所宣传的那样,但反序列化会产生此错误:“Newtonsoft.Json.JsonSerializationException:无法找到用于类型 FSI_0037+Foo 的构造函数。A class 应该有一个默认构造函数、一个带参数的构造函数或一个标有 JsonConstructor 属性的构造函数。"
有谁知道如何使反序列化工作?如果可以避免,我不想切换到 class 类型。但是,我已经尝试找出放置 JsonConstructor 属性的位置,但没有任何运气。我还尝试将 a settings value with the ConstructorHandling 值集传递给 AllowNonPublicDefaultConstructor,但没有任何改变。
为方便起见,我将Onur的解决方案复制到这里:
open Newtonsoft.Json
[<JsonObject(MemberSerialization = MemberSerialization.Fields)>]
type Foo = private Bar of string
let f = Bar "f"
let s = JsonConvert.SerializeObject(f)
let f2 = JsonConvert.DeserializeObject<Foo>(s)
printf "%A" f2
以防万一(自 2018 年以来情况似乎发生了变化),我使用的是 .NET 5。
我有理由相信您遇到了错误。
当我将您引用的示例代码复制到 LINQPad v6.13.13 和 运行 时,它运行良好。然后我尝试用另一个属性替换该属性 - 我在评论中提到的那个。不出所料,没有编译。所以我只是恢复到原来的属性。然后我遇到了与您遇到的相同的编译错误。那不应该发生。这是一个错误。但是在哪里?
进一步调查发现,如果我在LINQPad中执行以下操作,则会错误地产生编译错误:
- 从文件中打开代码片段,并尝试 运行 它。这编译并且运行没问题。
- 注释掉属性,并尝试运行它。这会产生有问题的编译错误。这是应该的。
- 带回属性,并尝试 运行 它。这应该可以编译并且 运行 当然可以,因为源代码现在与步骤 1 中的一样,但它仍然会产生有问题的编译错误。
无论我是否在 运行 秒之间重启 LINQPad,重复尝试相同的步骤都会产生同样的问题。
然后我尝试用 Visual Studio 重现问题。我没有成功——在VS 16.10.3
中没有这个问题暂时没有时间,稍后会继续调查。我想用最新的 LINQPad beta 来检查一下。
至于你的问题,是这个原因吗?
更新
我现在已经检查了 LINQPad v6.14.10,当前的测试版。该错误不存在。我并不感到意外。正如我在评论中提到的,编译器是我的主要嫌疑人。更重要的是,因为你告诉你在 VSCode 中有问题。但还有一个更有趣的细节。
LINQPad 多年来一直使用非常旧版本的 F# 编译器服务,因为存在一个阻止更新它的错误。 LINQPad 的创建者 Joseph Albahari 最近迫不及待地等待修复此错误,并找到了解决方法。该修复程序仅处于测试阶段。 F# 编译器服务版本的巨大飞跃自然意味着许多错误已得到修复,可能还有这个。
我不打算进一步探讨这个问题。我不使用 VSCode,但如果即使在最新的 REPL 中也存在这个问题,那么也许有人应该调查一下。