如何在F#中创建可为空的列表?

时间:2019-05-24 14:23:33

标签: f#

我有一个历史记录列表,我们可以从第3方软件中检索。此列表可以为null或非空。

在C#中,我会这样写,因为list可以为null:

List<HistoryEntry>

但是我在用F#编写时很费力。我已经尝试过:

* Nullable<HistoryEntry list>
* HistoryEntry list option
* HistoryEntry list?
* HistoryEntry list | null

但是,这些都不起作用。我们使用一个ListConverter,它几乎在所有地方都使用过,而且我不敢更改它(因为这会破坏所有内容):

type ListConverter() = 
    inherit JsonConverter()
    override __.CanConvert(t : Type) = (t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<list<_>>)

    override __.WriteJson(writer, value, serializer) = 
        let list = value :?> System.Collections.IEnumerable |> Seq.cast
        serializer.Serialize(writer, list)

    override __.ReadJson(reader, t, _, serializer) = 
        let itemType = t.GetGenericArguments().[0]
        let collectionType = typedefof<IEnumerable<_>>.MakeGenericType(itemType)
        let collection = serializer.Deserialize(reader, collectionType) :?> IEnumerable<_>
        let listType = typedefof<list<_>>.MakeGenericType(itemType)
        let cases = FSharpType.GetUnionCases(listType)

        let rec make = 
            function 
            | [] -> FSharpValue.MakeUnion(cases.[0], [||])
            | head :: tail -> 
                FSharpValue.MakeUnion(cases.[1], 
                                      [| head
                                         (make tail) |])
        make (collection |> Seq.toList)

我的问题是:如何创建该序列化程序可以理解的可空列表?

1 个答案:

答案 0 :(得分:2)

我实际上认为问题出在ListConverter,而不是您要使用的列表类型。 ListConverter不能说明整个集合为null,这在JSON中是完全有可能的。我认为最简单的更改是使用Seq.toList的自定义版本,该版本检查空值并将其转换为空列表。

let toJsonList s =
   if s |> box |> isNull
   then []
   else s |> Seq.toList

然后将ListConverter的最后一行更改为:

make (collection |> toJsonList)