在F#中反序列化为枚举选项 [英] Deserializing to enum option in F#

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

问题描述

几天前,我在F#中发布了一个关于用枚举进行反序列化的问题. 问题在这里:在F#与C#中进行反序列化

A couple days ago, I posted a question about deserialization with enums in F#. The question is here: Deserialization in F# vs. C#

答案指向Isaac Abraham编写的一些代码,位于: https://gist.github. com/isaacabraham/ba679f285bfd15d2f53e

The answer pointed to some code written by Isaac Abraham, at: https://gist.github.com/isaacabraham/ba679f285bfd15d2f53e

但是我面临另一个问题:

However I am facing another problem:

如果要反序列化的对象的对象类型为'enum option',则反序列化将失败,而如果类型只是'enum',则反序列化将起作用.

If the object to deserialize to has an object of type 'enum option', the deserialization will fail, whereas it'll work if the type is just 'enum'.

一个最小的例子:

type TestType =
    | A = 0
    | B = 1

type TestObjectA =
      {
           test : TestType
      }

type TestObjectB =
     {
         test : TestType option
     }


let x = "{\"test\":\"A\"}"
let TestA = Deserialize<TestObjectA> x // will work
let TestB = Deserialize<TestObjectB> x // will fail

,大型反序列化代码位于: https://pastebin.com/95JZLa6j

and the large deserialization code is at: https://pastebin.com/95JZLa6j

我把整个代码放在了一个小提琴中: https://dotnetfiddle.net/0Vc0Rh 但是它不能从那里运行,因为他们支持的F#版本将不接受'object'关键字.

I put the whole code in a fiddle: https://dotnetfiddle.net/0Vc0Rh but it can't be run from there since the F# version they support will not accept the 'object' keyword.

所以,我的问题是:为什么我不能在枚举上使用选项类型,但是可以在其他类型上使用呢?附带说明一下,由于我对F#还是很陌生,尽管我花了一些时间尝试对其进行故障排除,但是我并没有完全理解Isaac的代码.

So, my question is: why can't I use the option type on an enum, but it works on other types? As a side note, since I'm quite new to F#, I'm not fully understanding Isaac's code, although I spent some time going through it and trying to troubleshoot it.

我的理解是,这一行: |>顺序图(有趣(值,propertyInfo)-> Convert.ChangeType(值,propertyInfo.PropertyType))

My understanding is that this line: |> Seq.map (fun (value, propertyInfo) -> Convert.ChangeType(value, propertyInfo.PropertyType))

将尝试将类型转换为正确的枚举,而不转换为枚举选项.

will try to convert the type to the right enum, but not to the enum option.

作为一个额外的问题,是否存在一个可行的解决方案,可以对枚举进行完全惯用的反序列化? (不使用null类型)

As a bonus question, is there a working solution that does full idiomatic deserialization with enums? (without going through null types)

推荐答案

作为一个奖励问题,是否有一个可以解决问题的可行解决方案 枚举的惯用反序列化?

As a bonus question, is there a working solution that does full idiomatic deserialization with enums?

我在生产中使用了 Microsoft.FsharpLu.Json 包,并找到了它对于在普通" javascript和惯用F#之间进行序列化和反序列化非常有效.注意Microsoft.FsharpLu.Json依赖于引擎盖下的Newtonsoft.Json.

I use the Microsoft.FsharpLu.Json package in production and find it works quite well for serializing and deserializing between "plain" javascript and idiomatic F#. Note Microsoft.FsharpLu.Json relies on Newtonsoft.Json under the hood.

下面是使用类型和测试字符串的示例,使用期望进行测试.

Below is an example with your types and your test string, using Expecto for tests.

namespace FsharpLuJsonTest

open Newtonsoft.Json
open Microsoft.FSharpLu.Json
open Expecto
open Expecto.Flip

// Setup for FSharpLu.Json
type JsonSettings =
    static member settings =
        let s = JsonSerializerSettings(
                    NullValueHandling = NullValueHandling.Ignore,
                    MissingMemberHandling = MissingMemberHandling.Ignore)
        s.Converters.Add(CompactUnionJsonConverter())
        s
    static member formatting = Formatting.None

type JsonSerializer = With<JsonSettings>

// Your example
type TestType =
    | A = 0
    | B = 1

type TestObjectA = { test : TestType }
type TestObjectB = { test : TestType option }

module Tests =

    let x = """{"test":"A"}"""

    [<Tests>]
    let tests =
        testList "Deserialization Tests" [
            testCase "To TestObjectA" <| fun _ ->
                JsonSerializer.deserialize x
                |> Expect.equal "" { TestObjectA.test = TestType.A }

            testCase "To TestObjectB" <| fun _ ->
                JsonSerializer.deserialize x
                |> Expect.equal "" { TestObjectB.test = Some TestType.A }
        ]

module Main =

    [<EntryPoint>]
    let main args =
        runTestsInAssembly defaultConfig args

如您所见,FsharpLu.Json以您喜欢的方式开箱即用地支持区分联合和选项类型. FsharpLu.Json是一种灵活性较弱的解决方案,例如 Chiron (允许更多自定义),但我倾向于偏爱FsharpLu.Json的自以为是的方法.

As you can see FsharpLu.Json supports Discriminated Unions and option types out of the box in the way you prefer. FsharpLu.Json is a less flexible solution than some others like Chiron (which allow for much more customisation) but I tend to prefer the opinionated approach of FsharpLu.Json.

我还没有亲自使用它,但是新的 FSharp.SystemText.Json 库使用JsonUnionEncoding.ExternalTag设置应该与FsharpLu.Json大致相同.该库在幕后使用Microsoft的新System.Text.Json库,而不是Newtonsoft.Json.

I haven't used it personally, but the new FSharp.SystemText.Json library with the JsonUnionEncoding.ExternalTag setting should work roughly the same way FsharpLu.Json does. That library uses Microsoft's new System.Text.Json library under the hood rather than Newtonsoft.Json.

这篇关于在F#中反序列化为枚举选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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