为什么 F# Discriminated Union 无法让 JSON.NET 尊重其 TypeConverter 但其他类型可以?
Why does an F# Discriminated Union fails to have its TypeConverter respected by JSON.NET but other types can?
#r "../packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll"
type [<Struct; System.ComponentModel.TypeConverterAttribute(typeof<CC>)>] C = A of string
and CC() =
inherit System.ComponentModel.TypeConverter()
override _.CanConvertFrom (_, t) = t = typeof<string>
override _.ConvertFrom(_, _, s) = s :?> string |> A |> box<C>
override _.CanConvertTo (_, t) = t = typeof<string>
override _.ConvertTo(_, _, s, _) = s :?> C |> fun (A s) -> s |> box<string>
Newtonsoft.Json.JsonConvert.SerializeObject {|a = A "123"|}
这导致 val it : string = "{"a":{"Case":"A","Fields":["123"]}}"
,这表明 TypeConverter
未得到遵守。对于参考 DU 也会发生这种情况。
但是,JsonConverter
s 不会发生这种情况:
#r "../packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll"
type [<Struct; Newtonsoft.Json.JsonConverter(typeof<CC>)>] C = A of string
and CC() =
inherit Newtonsoft.Json.JsonConverter()
override _.CanConvert t = t = typeof<string>
override _.ReadJson (r, _, _, _) = r.ReadAsString() |> A |> box<C>
override _.WriteJson (w, v, _) = v :?> C |> fun (A s) -> s |> w.WriteValue
Newtonsoft.Json.JsonConvert.SerializeObject {|a = A "123"|}
这导致 val it : string = "{"a":"123"}"
。
将此与记录进行比较:
#r "../packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll"
type [<Struct; System.ComponentModel.TypeConverterAttribute(typeof<CC>)>] C = { A: string }
and CC() =
inherit System.ComponentModel.TypeConverter()
override _.CanConvertFrom (_, t) = t = typeof<string>
override _.ConvertFrom(_, _, s) = { A = s :?> string } |> box<C>
override _.CanConvertTo (_, t) = t = typeof<string>
override _.ConvertTo(_, _, s, _) = (s :?> C).A |> box<string>
Newtonsoft.Json.JsonConvert.SerializeObject {|a = { A = "123"}|}
这也导致 val it : string = "{"a":"123"}"
,这表明 TypeConverter
受到尊重。
这表明某些东西正在阻止识别受歧视工会中的 TypeConverter
s。会是什么原因呢? JsonConverter
s 在字典键中不可用,所以我希望 TypeConverter
s 表现更好。正确序列化上述受歧视联合的可行方法是什么?
你的问题是 Json.NET 有它自己的内置转换器来区分联合,DiscriminatedUnionConverter
。任何适用的 JsonConverter
将始终取代已应用的 TypeConverter
.
可以通过在 settings or via an applied JsonConverterAttribute
. You have already created a converter that correctly converts your type C
, but if you would prefer to fall back to the applied TypeConverter
, you can create a JsonConverter
that does nothing and falls back on default serialization by returning false
from CanRead
and CanWrite
:
中提供您自己的备用 JsonConverter
来禁用内置转换器
type NoConverter<'a> () =
inherit JsonConverter()
override this.CanConvert(t) = (t = typedefof<'a>)
override this.CanRead = false
override this.CanWrite = false
override this.WriteJson(_, _, _) = raise (NotImplementedException());
override this.ReadJson(_, _, _, _) = raise (NotImplementedException());
然后按如下方式将其应用到您的类型中(演示 fiddle #1 here):
type [<JsonConverterAttribute(typeof<NoConverter<C>>); System.ComponentModel.TypeConverterAttribute(typeof<CC>)>] C = A of string
and CC() =
inherit System.ComponentModel.TypeConverter()
override this.CanConvertFrom (_, t) = (t = typeof<string>)
override this.ConvertFrom(_, _, s) = s :?> string |> A |> box<C>
override this.CanConvertTo (_, t) = t = typeof<string>
override this.ConvertTo(_, _, s, _) = s :?> C |> fun (A s) -> s |> box<string>
printfn "%s" (Newtonsoft.Json.JsonConvert.SerializeObject(A "123"))
或者,在设置中使用它如下(demo fiddle #2 here):
let settings = JsonSerializerSettings(Converters = [|NoConverter<C>()|])
printfn "%s" (Newtonsoft.Json.JsonConvert.SerializeObject(A "123", settings))
#r "../packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll"
type [<Struct; System.ComponentModel.TypeConverterAttribute(typeof<CC>)>] C = A of string
and CC() =
inherit System.ComponentModel.TypeConverter()
override _.CanConvertFrom (_, t) = t = typeof<string>
override _.ConvertFrom(_, _, s) = s :?> string |> A |> box<C>
override _.CanConvertTo (_, t) = t = typeof<string>
override _.ConvertTo(_, _, s, _) = s :?> C |> fun (A s) -> s |> box<string>
Newtonsoft.Json.JsonConvert.SerializeObject {|a = A "123"|}
这导致 val it : string = "{"a":{"Case":"A","Fields":["123"]}}"
,这表明 TypeConverter
未得到遵守。对于参考 DU 也会发生这种情况。
但是,JsonConverter
s 不会发生这种情况:
#r "../packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll"
type [<Struct; Newtonsoft.Json.JsonConverter(typeof<CC>)>] C = A of string
and CC() =
inherit Newtonsoft.Json.JsonConverter()
override _.CanConvert t = t = typeof<string>
override _.ReadJson (r, _, _, _) = r.ReadAsString() |> A |> box<C>
override _.WriteJson (w, v, _) = v :?> C |> fun (A s) -> s |> w.WriteValue
Newtonsoft.Json.JsonConvert.SerializeObject {|a = A "123"|}
这导致 val it : string = "{"a":"123"}"
。
将此与记录进行比较:
#r "../packages/Newtonsoft.Json.12.0.3/lib/netstandard2.0/Newtonsoft.Json.dll"
type [<Struct; System.ComponentModel.TypeConverterAttribute(typeof<CC>)>] C = { A: string }
and CC() =
inherit System.ComponentModel.TypeConverter()
override _.CanConvertFrom (_, t) = t = typeof<string>
override _.ConvertFrom(_, _, s) = { A = s :?> string } |> box<C>
override _.CanConvertTo (_, t) = t = typeof<string>
override _.ConvertTo(_, _, s, _) = (s :?> C).A |> box<string>
Newtonsoft.Json.JsonConvert.SerializeObject {|a = { A = "123"}|}
这也导致 val it : string = "{"a":"123"}"
,这表明 TypeConverter
受到尊重。
这表明某些东西正在阻止识别受歧视工会中的 TypeConverter
s。会是什么原因呢? JsonConverter
s 在字典键中不可用,所以我希望 TypeConverter
s 表现更好。正确序列化上述受歧视联合的可行方法是什么?
你的问题是 Json.NET 有它自己的内置转换器来区分联合,DiscriminatedUnionConverter
。任何适用的 JsonConverter
将始终取代已应用的 TypeConverter
.
可以通过在 settings or via an applied JsonConverterAttribute
. You have already created a converter that correctly converts your type C
, but if you would prefer to fall back to the applied TypeConverter
, you can create a JsonConverter
that does nothing and falls back on default serialization by returning false
from CanRead
and CanWrite
:
JsonConverter
来禁用内置转换器
type NoConverter<'a> () =
inherit JsonConverter()
override this.CanConvert(t) = (t = typedefof<'a>)
override this.CanRead = false
override this.CanWrite = false
override this.WriteJson(_, _, _) = raise (NotImplementedException());
override this.ReadJson(_, _, _, _) = raise (NotImplementedException());
然后按如下方式将其应用到您的类型中(演示 fiddle #1 here):
type [<JsonConverterAttribute(typeof<NoConverter<C>>); System.ComponentModel.TypeConverterAttribute(typeof<CC>)>] C = A of string
and CC() =
inherit System.ComponentModel.TypeConverter()
override this.CanConvertFrom (_, t) = (t = typeof<string>)
override this.ConvertFrom(_, _, s) = s :?> string |> A |> box<C>
override this.CanConvertTo (_, t) = t = typeof<string>
override this.ConvertTo(_, _, s, _) = s :?> C |> fun (A s) -> s |> box<string>
printfn "%s" (Newtonsoft.Json.JsonConvert.SerializeObject(A "123"))
或者,在设置中使用它如下(demo fiddle #2 here):
let settings = JsonSerializerSettings(Converters = [|NoConverter<C>()|])
printfn "%s" (Newtonsoft.Json.JsonConvert.SerializeObject(A "123", settings))