IgnoreMissingMember 設定似乎無法與 FSharpLu.Json 解串器一起使用



这是以下问题:反序列化问题,json.net,在 F# 中。

我正在使用FSharpLu.Json反序列化一些具有额外未绑定属性的JSON。 这是代码:

open System
open Newtonsoft.Json
open Microsoft.FSharpLu.Json
type r =
{
a: int
}
let a =
"{"a":3, "b":5}" 
Compact.TupleAsArraySettings.settings.MissingMemberHandling <- MissingMemberHandling.Ignore
Compact.deserialize<r> a  // doesn't work

尽管设置了MissingMemberHandling.Ignore它仍返回 json.net 错误:

在类型为"r"的对象上找不到成员"b"。路径"b",第 1 行,位置 13。

有没有办法做到这一点,还是FSharpLu.Json的问题?

这是小提琴:https://dotnetfiddle.net/OsVv1M

作为旁注,FSharpLu.Json 中还有另一个反序列化程序,我可以让该代码使用它:

FSharpLu.Json.Default.Internal.DefaultSettings.settings.MissingMemberHandling <- MissingMemberHandling.Ignore
Default.deserialize<r> a

将起作用,但该反序列化器不处理可区分的联合......所以我需要让紧凑的那个工作。

在查看FSharpLu.Json的来源时,我发现了这个:

/// Compact serialization where tuples are serialized as heterogeneous arrays
type TupleAsArraySettings =
static member formatting = Formatting.Indented
static member settings =
JsonSerializerSettings(
NullValueHandling = NullValueHandling.Ignore,
// MissingMemberHandling is not technically needed for
// compact serialization but it avoids certain ambiguities
// that guarantee that deserialization coincides with the
// default Json.Net deserialization.
// (where 'coincides' means 'if the deserialization succeeds they both return the same object')
// This allows us to easily define the BackwardCompatible
// serializer (that handles both Compact and Default Json format) by reusing
// the Compact deserializer.
MissingMemberHandling = MissingMemberHandling.Error,
Converters = [| CompactUnionJsonConverter(true, true) |]
)

所以他们显式地将 MissingMemberHandling 设置为 Error; 也许解决方案是实例化反序列化程序,更改设置,然后使用它。

您尝试更改的序列化程序设置Compact.TupleAsArraySettings.settings是一个静态成员,如代码所示:

type TupleAsArraySettings =
static member formatting = Formatting.Indented
static member settings =
JsonSerializerSettings(
NullValueHandling = NullValueHandling.Ignore,
// MissingMemberHandling is not technically needed for
// compact serialization but it avoids certain ambiguities
// that guarantee that deserialization coincides with the
// default Json.Net deserialization.
// (where 'coincides' means 'if the deserialization succeeds they both return the same object')
// This allows us to easily define the BackwardCompatible
// serializer (that handles both Compact and Default Json format) by reusing
// the Compact deserializer.
MissingMemberHandling = MissingMemberHandling.Error,
Converters = [| CompactUnionJsonConverter(true, true) |]
)

由于member实际上是一个成员函数(即方法(,如 F# 所述,为了好玩和获利:将函数附加到类型settings实际上(在 C# 术语中(是一个静态属性,每次调用时都会返回一个新的JsonSerializerSettings实例。 为了测试这一点,我们可以做:

printfn "%b" (Object.ReferenceEquals(Compact.TupleAsArraySettings.settings, Compact.TupleAsArraySettings.settings)) // prints "false"

哪个打印"假"。 因此,改变返回值对Compact的行为没有影响。 c# 意义上的静态字段将由static let语句定义;如果settings返回这样的字段,则更改其内容将产生影响。

在任何情况下,修改Compact.TupleAsArraySettings.settings.MissingMemberHandling的值似乎都是不明智的,因为这样做会修改整个 AppDomain 中Compact.deserialize的行为,从而可能破坏与本机序列化 Json.NET 向后兼容性。 如上面的代码注释中所述,需要该设置才能使BackwardCompatible.deserialize工作。 但为什么会这样呢? 由于 Json.NET 的option和歧视工会的原生格式如下所示:

{
"a": {
"Case": "Some",
"Fields": [
3
]
}
}

我们可以猜测,MissingMemberHandling用于捕获发现或未发现"Case""Fields"的情况,并从一种算法切换到另一种算法。

如果您确定不需要以 Json.NET 格式反序列化 f# 类型,则似乎应该能够直接使用CompactUnionJsonConverter,如下所示:

let settings = JsonSerializerSettings(
NullValueHandling = NullValueHandling.Ignore,
Converters = [| CompactUnionJsonConverter(true, true) |]
)
let c = JsonConvert.DeserializeObject<r>(a, settings)
let json2 = JsonConvert.SerializeObject(c, Formatting.Indented, settings)

演示小提琴在这里。

最新更新