c# - Json.NET 根据属性类型使属性成为必需的

标签 c# serialization asp.net-core f# json.net

我正在为 .Net 核心中的自定义 json 序列化而苦苦挣扎,我试图使所有属性成为默认必需的,除非属性具有特定类型。这是我要实现的目标的示例:

让我们假设我有以下类型: F#:

type FooType = {
   id: int
   name: string 
   optional: int option 
}

您可以将以下代码视为类似于 C# 中的以下代码:

class FooType =
{
   int Id {get;set;};
   string Name {get;set;};
   Nullable<int> Optional {get;set;};
}

我想做的是,如果 json 对象中缺少 Id 或 Name 属性,则返回错误,但如果缺少 Optional,则反序列化时不会出现错误(因此基本上是根据其类型根据需要设置属性)。通过使用此示例中的 RequireObjectPropertiesContractResolver,我能够根据需要标记所有属性:https://stackoverflow.com/a/29660550但不幸的是,我无法构建更有活力的东西。

我也有可选类型的默认转换器,我想添加到序列化中。这不是这个特定问题的一部分,但如果您知道如何标记属性是否需要以及如何在一个地方使用自定义转换器,那就更好了。

最佳答案

您可以结合 Json.NET require all properties on deserialization 中的契约(Contract)解析器使用 Reflection to find out if property is of option type 的答案中的逻辑通过 p.s.w.g标记除根据需要可选的成员之外的所有成员:

type RequireObjectPropertiesContractResolver() =
    inherit DefaultContractResolver()

    override __.CreateObjectContract(objectType: Type) = 
        let contract = base.CreateObjectContract objectType
        contract.ItemRequired <- System.Nullable<Required>(Required.Always)
        contract

    override __.CreateProperty(memberInfo: MemberInfo, memberSerialization: MemberSerialization) =
        let property = base.CreateProperty(memberInfo, memberSerialization)
        // https://stackoverflow.com/questions/20696262/reflection-to-find-out-if-property-is-of-option-type
        let isOption = property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() = typedefof<Option<_>>
        if isOption then (
            property.Required <- Required.Default        
            property.NullValueHandling <- new System.Nullable<NullValueHandling>(NullValueHandling.Ignore)
        )
        property

然后,反序列化如下:

let settings = new JsonSerializerSettings(ContractResolver = RequireObjectPropertiesContractResolver())
let obj = JsonConvert.DeserializeObject<FooType>(inputJson, settings)

注意事项:

  • 我还添加了 NullValueHandling.Ignore这样没有值的可选成员就不会被序列化。

  • 您可能想要 cache the contract resolver for best performance .

  • Option<'T>Nullable<'T> 不同.我检查了 typedefof<Option<_>>但您可以为 typedefof<System.Nullable<_>> 添加支票如果您愿意,也可以:

    let isOption = property.PropertyType.IsGenericType && (property.PropertyType.GetGenericTypeDefinition() = typedefof<Option<_>> || property.PropertyType.GetGenericTypeDefinition() = typedefof<System.Nullable<_>>)
    

样本 fiddle , 这表明字符串 {"id":101,"name":"John"}可以反序列化,但是字符串 {"id":101}不能。

关于c# - Json.NET 根据属性类型使属性成为必需的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48327799/

相关文章:

c# - 使用 ClosedXML C# 在范围内查找字符串

c# - 从 GOLD-Parser CGT-File 中提取关键词

c# - 如何使 Asp.Net Core Identity 与 OpenIdConnect 一起工作

c# - 是否可以将 Swagger 与 AspNetCore Odata 一起使用?

c# - 使用字符串中的公钥验证 JWT

c# - 在 ASP.Net Core 1.0 中注册通用 EntityFrameworkCore DbContext

c# - WCF 对象序列化问题

ios - 如何将快速结构保存到文件

java - 使用 Jackson 将 XML 属性添加到手动构建的节点树

c# - 如何从 asp.net core 中的 Roles 对象获取角色名称