简体   繁体   English

F#:如何使用 Newtonsoft.Json 反序列化私有歧视联合?

[英]F#: How to deserialize a private discriminated union with Newtonsoft.Json?

In his question and answer from 2018 , Onur Gumus used [<JsonObject(MemberSerialization = MemberSerialization.Fields)>] to enable serialization/deserialization of a discriminated union with a private constructor.2018 年的问答中Onur Gumus使用 [<JsonObject(MemberSerialization = MemberSerialization.Fields)>] 来启用具有私有构造函数的可区分联合的序列化/反序列化。

For me, the serialization works as advertised, but deserialization produces this error: " Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type FSI_0037+Foo. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. "对我来说,序列化如宣传的那样工作,但反序列化会产生以下错误:“ Newtonsoft.Json.JsonSerializationException:无法找到用于 FSI_0037+Foo 类型的构造函数。一个类应该有一个默认构造函数、一个带参数的构造函数或一个用 JsonConstructor 属性标记的构造函数。

Does anyone know how to get the deserialization working?有谁知道如何让反序列化工作? I don't want to switch to a class type if it can be avoided.如果可以避免,我不想切换到类类型。 However, I've tried figuring out where to place a JsonConstructor attribute without any luck.但是,我已经尝试找出放置 JsonConstructor 属性的位置,但没有任何运气。 I also tried passing a settings value with the ConstructorHandling value set to AllowNonPublicDefaultConstructor, but that changed nothing.我还尝试传递一个ConstructorHandling值设置为 AllowNonPublicDefaultConstructor 的设置值,但这没有任何改变。

For convenience, I copy Onur's solution here:为方便起见,我在这里复制 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

In case it matters (since things seem to have changed since 2018), I'm using .NET 5.万一重要(因为自 2018 年以来事情似乎发生了变化),我正在使用 .NET 5。

I am reasonably sure you have stumbled onto a bug.我有理由确定你偶然发现了一个错误。

When I copied the sample code you refer to into LINQPad v6.13.13, and ran it, then it worked fine.当我将您引用的示例代码复制到 LINQPad v6.13.13 中并运行时,它运行良好。 I then tried to replace the attribute with another attribute - the one I mentioned in the comment.然后我尝试用另一个属性替换该属性 - 我在评论中提到的那个。 Not unexpectedly that didn't compile.没想到没有编译。 So I just reverted to the original attribute.所以我只是恢复到原来的属性。 Then I got the same compile error you encountered.然后我遇到了与您遇到的相同的编译错误。 That should not have happened.那不应该发生。 It's a bug.这是一个错误。 But where?但是哪里?

Further investigation has revealed that the compile error is produced erroneously if I do the following in LINQPad:进一步调查显示,如果我在 LINQPad 中执行以下操作,则会错误地产生编译错误:

  1. Open the code snippet from a file, and try to run it.从文件中打开代码片段,然后尝试运行它。 This compiles and runs fine.这编译并运行良好。
  2. Comment out the attribute, and try to run it.注释掉该属性,然后尝试运行它。 This produces the compile error in question.这会产生有问题的编译错误。 This is as it should be.这是应该的。
  3. Bring back the attribute, and try to run it.带回属性,并尝试运行它。 This should compile and run fine of course, since the source is now as it was in step 1, but it still produces the compile error in question.这当然应该编译并运行良好,因为源现在与步骤 1 中的一样,但它仍然会产生有问题的编译错误。

Trying the same steps repeatedly will produce the same problem, whether I restart LINQPad between runs or not.重复尝试相同的步骤会产生相同的问题,无论我是否在两次运行之间重新启动 LINQPad。

Then I tried to reproduce the problem with Visual Studio.然后我尝试用 Visual Studio 重现这个问题。 I did not succeed - there is no such problem in VS 16.10.3我没有成功 - 在 VS 16.10.3 中没有这样的问题

I have no more time at the moment, but will continue to investigate later.我现在没有更多时间,但稍后会继续调查。 I want to check this with the latest LINQPad beta.我想用最新的 LINQPad 测试版来检查一下。

As for your question, was this the cause?至于你的问题,是这个原因吗?

UPDATE更新

I have now checked with LINQPad v6.14.10, the current beta version.我现在已经检查了当前的测试版 LINQPad v6.14.10。 The bug is not present there.该错误不存在于那里。 I am not surprised.我并不感到意外。 As I've mentioned in a comment, the compiler is my prime suspect.正如我在评论中提到的,编译器是我的主要嫌疑人。 Even more so because you tell you have the problem in VSCode.更是如此,因为你告诉你 VSCode 有问题。 But there is an even more interesting detail.但还有一个更有趣的细节。

LINQPad has used a very old version of the F# compiler service for ages, because there was a bug that prevented updating it. LINQPad 使用一个非常旧版本的 F# 编译器服务已经有很长时间了,因为有一个错误阻止了它的更新。 Joseph Albahari, the creator of LINQPad, recently got impatient waiting for a fix for this bug, and found a workaround. LINQPad 的创建者 Joseph Albahari 最近迫不及待地等待修复此错误,并找到了解决方法。 That fix is only in the beta.该修复程序仅在测试版中。 The huge leap in the F# compiler service version naturally means lots of bugs has been fixed, and likely this one too. F# 编译器服务版本的巨大飞跃自然意味着许多错误已得到修复,很可能也是这个错误。

I am not going to pursue this further.我不打算进一步探讨这个问题。 I don't use VSCode, but if this problem is present even in the latest REPL there, then maybe somebody should look into it.我不使用 VSCode,但如果即使在最新的 REPL 中也存在这个问题,那么也许有人应该调查一下。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM