如何使用Json.Net将缺失的属性反序列化为F#记录中的空列表而不是null

肖恩·基伦(Sean Kearon)

考虑包含如下列表值的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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

您如何将JSON反序列化为F#中的记录的地图/字典?

使用json.net和包含@符号的json属性反序列化为F#类型

使用自定义ContractResolver,当将空JSON属性反序列化为值类型成员时,如何设置默认值而不是null?

F#将JSON字符串反序列化为正确的记录类型

如何仅将 JSON 数据的某些属性反序列化为 C# 中的列表

Json.NET将数组反序列化为属性

将json.net属性反序列化为大写

如何使用 JSON.NET 将具有空值的 json 数组反序列化为不可为空的 int 列表?

无法使用Json.Net将certian json属性反序列化为c#属性

使用Newtosoft Json将Json反序列化为null

如何(完全)将json反序列化为通用列表?

使用JsonConverter json.net将JSON反序列化为对象列表

如何使用System.Runtime.Serialization.Json将JSON数组反序列化为列表

如何正确地将F#记录序列化为JSON?

如何将JSON反序列化为.net对象

如何使用 JSON.net 将 JSON 反序列化为嵌套类?

如何使用Json.Net将JSON数组反序列化为对象?

如何使用SubType将json反序列化为对象?

如何使用JavaScriptSerializer将JSON反序列化为元组

如何使用 json.net(而不是 JObject)反序列化为对象

使用 json.net 将 JSON 反序列化为 c# 中的对象

F#将JSON反序列化为字符串或节点

如何通过使用Jackson将JSON数组反序列化为单个链接列表

使用Newtonsoft将Json反序列化为C#中的对象列表

使用Json.NET将F#区分的联合序列化为字符串

将列表<string>从Json反序列化为列表<object>

将具有属性名称作为数字的JSON对象反序列化为VB.NET中的对象

如何使用Jackson将反序列化的JSON反序列化为忽略键的对象?

当JSON使用日期作为属性名称时,如何使用GSON将JSON反序列化为Java Object?