我需要一个函数将类型从第三方库转换为IDictionary
,以便可以轻松地序列化(到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
或字典。
随着类型的添加(ugh),此功能将继续增长。它不是类型安全的(需要全能模式)。确定支持哪些类型需要仔细考虑单片模式匹配。
我希望能够做到这一点:
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
所以,我在这里寻找创造力。是否有更好的方式来写这个来解决我的抱怨?
答案 0 :(得分: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")
答案 1 :(得分:2)
快速明智的想法:使用重载
//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)]