考虑包含如下列表值的F#记录:
type MyRecord = {
Name: string
SomeList: string list
}
使用Netwonsoft.Json.JsonConvert
到deserialise JSON这一记录时,JSON不包含列表值的属性Values
的记录将导致具有的deserialised记录null
的列表,而不是一个空的列表值[]
。
那是,
open Newtonsoft.Json
JsonConvert.DeserializeObject<MyRecord>("""{ "Name": "Some name"}""" ) |> printfn "%A"
// Gives: { Name = "Some name"; SomeList = null; }
您如何反序列化使用,Netwonsoft.Json
以便将列表初始化为空列表?例如:
{ Name = "Some name"; SomeList = []; }
您可以使用自定义合同解析器执行此操作,例如:
type ParameterizedConstructorInitializingContractResolver() =
inherit DefaultContractResolver()
// List is a module not a static class so it's a little inconvenient to access via reflection. Use this wrapper instead.
static member EmptyList<'T>() = List.empty<'T>
override __.CreatePropertyFromConstructorParameter(matchingMemberProperty : JsonProperty, parameterInfo : ParameterInfo) =
let property = base.CreatePropertyFromConstructorParameter(matchingMemberProperty, parameterInfo)
if (not (matchingMemberProperty = null) && property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() = typedefof<_ list>) then
let genericMethod = typeof<ParameterizedConstructorInitializingContractResolver>.GetMethod("EmptyList", BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.Static)
let concreteMethod = genericMethod.MakeGenericMethod(property.PropertyType.GetGenericArguments())
let defaultValue = concreteMethod.Invoke(null, null)
property.DefaultValue <- defaultValue
property.DefaultValueHandling <- new System.Nullable<DefaultValueHandling>(DefaultValueHandling.Populate)
matchingMemberProperty.DefaultValue <- defaultValue
matchingMemberProperty.DefaultValueHandling <- new System.Nullable<DefaultValueHandling>(DefaultValueHandling.Populate)
property
然后按如下方式使用它:
let settings = JsonSerializerSettings(ContractResolver = new ParameterizedConstructorInitializingContractResolver())
let myrecord1 = JsonConvert.DeserializeObject<MyRecord>("""{ "Name": "Missing SomeList"}""", settings )
let myrecord2 = JsonConvert.DeserializeObject<MyRecord>("""{ "Name": "Populated SomeList", "SomeList" : ["a", "b", "c"]}""", settings )
let myrecord3 = JsonConvert.DeserializeObject<MyRecord>("""{ "Name": "null SomeList", "SomeList" : null}""", settings )
笔记:
合同解析器适用于通过参数化构造函数反序列化的任何对象,包括但不限于f#记录。如果任何此类对象的构造函数参数的类型T list
均为any,T
则该值将默认为List.empty<T>
missing或null。
合同解析器List.empty<T>
为所有反序列化的对象重用默认值的相同实例,这在这里很好,因为f#列表是不可变的(List.empty<T>
无论如何似乎都是单例)。为可变集合提供默认值作为构造函数参数时,相同的方法将不起作用。
您可能需要缓存合同解析器以获得最佳性能。
构造函数参数必须与相应的属性具有相同的名称(模数大小写)。
演示在这里摆弄。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句