IgnoreMissingMember 设置似乎不适用于 FSharpLu.Json 反序列化器

2024-03-13

这是以下内容:F# 中 json.net 的反序列化问题 https://stackoverflow.com/questions/62360805/deserialization-issue-with-json-net-in-f.

我正在反序列化一些具有额外的未绑定属性的 JSON,使用FSharpLu.Json https://www.nuget.org/packages/Microsoft.FSharpLu.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 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, is a 静态成员,如图所示code https://github.com/microsoft/fsharplu/blob/master/FSharpLu.Json/Compact.fs#L338:

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) |]
        )

Since a member实际上是一个成员函数(即方法)正如所解释的F# 的乐趣和利润:将函数附加到类型 https://fsharpforfunandprofit.com/posts/type-extensions/, settings实际上(用 C# 术语来说)是一个返回新实例的静态属性JsonSerializerSettings每次调用它时。为了测试这一点,我们可以这样做:

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

打印“假”。因此改变返回值对行为没有影响Compact。 C# 意义上的静态字段将由static let陈述;如果settings返回这样一个字段,改变它的内容就会产生效果。

在任何情况下修改的值Compact.TupleAsArraySettings.settings.MissingMemberHandling似乎不明智,因为这样做会改变 of 的行为Compact.deserialize以一种可能会破坏的方式贯穿整个 AppDomain向后兼容性 https://github.com/Microsoft/fsharplu/wiki/fsharplu.json#backward-compatibility-with-jsonnet使用 Json.NET 本机序列化。正如上面代码注释中所解释的,需要进行设置BackwardCompatible.deserialize https://github.com/microsoft/fsharplu/blob/master/FSharpLu.Json/BackwardCompatible.fs#L50工作。但为什么会这样呢?由于 Json.NET 的本机格式为option受歧视的工会看起来像:

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

我们可以猜测MissingMemberHandling用于捕获以下情况"Case" and "Fields"是否找到,并从一种算法切换到另一种算法。

如果您确定不需要以 Json.NET 格式反序列化 f# 类型,看来你应该能够使用CompactUnionJsonConverter https://github.com/microsoft/fsharplu/blob/master/FSharpLu.Json/Compact.fs#L77直接如下:

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)

演示小提琴here https://dotnetfiddle.net/FFpG52.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IgnoreMissingMember 设置似乎不适用于 FSharpLu.Json 反序列化器 的相关文章

随机推荐