1

我需要一个函数将类型从第三方库转换为IDictionarys,以便它们可以轻松序列化(转换为 JSON)。类型之间存在依赖关系,因此字典有时是嵌套的。

现在我有一些像这样可怕的东西:

//Example type
type A(name) = 
  member __.Name  = name

//Example type
type B(name, alist) =
  member __.Name = name
  member __.AList : A list = alist

let rec ToSerializable x =
  match box x with
  | :? A as a -> dict ["Name", box a.Name]
  | :? B as b -> dict ["Name", box b.Name; "AList", box (List.map ToSerializable b.AList)]
  | _ -> failwith "wrong type"

这会将所有内容转换为原始类型、IEnumerable此类类型或字典。

随着类型的添加,此功能将不断增长(呃)。它不是类型安全的(需要包罗万象的模式)。弄清楚支持哪些类型需要仔细阅读整体模式匹配。

我很想能够做到这一点:

type ThirdPartyType with
  member x.ToSerializable() = ...

let inline toSerializable x =
  (^T : (member ToSerializable : unit -> IDictionary<string,obj>) x)

let x = ThirdPartyType() |> toSerializable //type extensions don't satisfy static member constraints

所以,我在这里寻找创意。有没有更好的方法来写这个来解决我的抱怨?

4

2 回答 2

3

这是解决类型安全问题的一种可能解决方案,但不一定是您的可扩展性问题:

// these types can appear in any assemblies
type A = { Name : string }
type B = { Name : string; AList : A list }
type C(name:string) =
    member x.Name = name
    static member Serialize(c:C) = dict ["Name", box c.Name]

 

// all of the following code goes in one place
open System.Collections.Generic

type SerializationFunctions = class end

let inline serializationHelper< ^s, ^t when (^s or ^t) : (static member Serialize : ^t -> IDictionary<string,obj>)> t = 
    ((^s or ^t) : (static member Serialize : ^t -> IDictionary<string,obj>) t)
let inline serialize t = serializationHelper<SerializationFunctions,_> t

// overloads for each type that doesn't define its own Serialize method
type SerializationFunctions with
    static member Serialize (a:A) = dict ["Name", box a.Name]
    static member Serialize (b:B) = dict ["Name", box b.Name; "AList", box (List.map serialize b.AList)]

let d1 = serialize { A.Name = "a" }
let d2 = serialize { B.Name = "b"; AList = [{ A.Name = "a" }]}
let d3 = serialize (C "test")
于 2012-04-05T01:30:29.847 回答
2

作为快速n-明显的想法:使用重载

//Example type
type A(name) = 
  member __.Name  = name

//Example type
type B(name, alist) =
  member __.Name = name
  member __.AList : A list = alist

type Converter =
    static member ToSerializable(a : A) = dict ["Name", box a.Name]
    static member ToSerializable(b : B) = dict ["Name", box b.Name; "AList", box (b.AList |> List.map Converter.ToSerializable)]
于 2012-04-05T01:31:35.727 回答