如何检查 JSON 中的值类型并决定是不是反序列化?

Posted

技术标签:

【中文标题】如何检查 JSON 中的值类型并决定是不是反序列化?【英文标题】:How to check the value type in a JSON and decide whether to deserialize?如何检查 JSON 中的值类型并决定是否反序列化? 【发布时间】:2022-01-12 13:04:42 【问题描述】:

给定以下结构:

"meta": 
  "pagination": 
    "total": 378,
    "count": 50,
    "per_page": 50,
    "current_page": 2,
    "total_pages": 8,
    "links": 
        "previous": "https://myapi.com.br/api/clients?page=1",
        "next": "https://myapi.com.br/api/clients?page=3"
    

有时属性“links”的值作为空数组返回。

"meta": 
  "pagination": 
    "total": 14,
    "count": 14,
    "per_page": 50,
    "current_page": 1,
    "total_pages": 1,
    "links": []
  

所以我创建了一个从 JsonConverter 继承的类型来设置在我的类属性中。 这是我不知道如何进行的地方。

public class LinksJsonConverter : JsonConverter

    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType)
        => objectType == typeof(Links);

    public override object ReadJson(JsonReader reader, Type objectType, 
        object existingValue, JsonSerializer serializer)
    
        var links = new Links();
        if (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.EndArray)
            return links; // try return null
        JObject jo = JObject.Load(reader);
        links.Previous = jo["Previous"]?.ToString() ?? string.Empty;
        links.Next = jo["Next"]?.ToString();?? string.Empty;          
        return links;
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        => ...

课程:

public class Links

    public string Previous  get; set; 
    public string Next  get; set; 


public class Pagination

    public int Total  get; set; 
    public int Count  get; set; 

    [JsonProperty("per_page")]
    public int PerPage  get; set; 

    [JsonProperty("current_page")]
    public int CurrentPage  get; set; 

    [JsonProperty("total_pages")]
    public int TotalPages  get; set; 
    
    [JsonConverter(typeof(LinksJsonConverter))]
    public Links Links  get; set; 

当我尝试从空的“链接”属性转换时出现错误。 当值为空数组时:

Message: 
Test method IntegrationDownloaderServiceTests.ShouldProcessResultNfe threw exception: 
Newtonsoft.Json.JsonSerializationException: Unexpected token when deserializing object: 
EndArray. Path 'meta.pagination.links', line 123, position 17.

如何解决这种情况?

【问题讨论】:

显示您对链接的定义 只是为了确定:links 属性值可以是对象,也可以是数组(第一个结构中没有错字)?所以你的问题是如何反序列化类型未知的属性(可能是数组或对象? @LaurentGabiot 是的,没错 当没有更多页面时,API 可能会将此值作为空数组返回。 【参考方案1】:

第一步将链接反序列化为对象:

public class Pagination

    public int total  get; set; 
    public int count  get; set; 
    public int per_page  get; set; 
    public int current_page  get; set; 
    public int total_pages  get; set; 
    public object links  get; set; 


public class Meta

    public Pagination pagination  get; set; 


public class Root

    public Meta meta  get; set; 

然后检查链接类型:(this)

public static class TypeExtensions

    public static bool IsArrayOf<T>(this Type type)
    
         return type == typeof (T[]);
    
 

并决定是否将对象转换为数组。

【讨论】:

IsArrayOf&lt;T&gt;(this Type type) 有点荒谬,您实际上并没有在这里检查links,只是一些任意传递的类型变量。 IsArrayOf&lt;T&gt;(this object o)(然后使用 typeof(o) == typeof(T[]) 甚至只是 o is T[])更有意义。【参考方案2】:

我可能对我的问题不够清楚。 我想忽略数组值(至少现在),直到它有意义的那一天。 在这个 API 的文档中,我没有找到关于它的参考资料。 我会尝试联系开发者。

这样就成功了:

public override object ReadJson(JsonReader reader, Type objectType, 
    object existingValue, JsonSerializer serializer)

    if (reader.TokenType == JsonToken.StartObject)
    
        JObject jo = JObject.Load(reader);
        var links = new Links
        
            Previous = jo["previous"]?.Value<string>() ?? string.Empty,
            Next = jo["next"]?.Value<string>() ?? string.Empty
        ;
        return links;
    
    else if (reader.TokenType == JsonToken.StartArray)
    
        reader.Skip();
    

    return null;

【讨论】:

以上是关于如何检查 JSON 中的值类型并决定是不是反序列化?的主要内容,如果未能解决你的问题,请参考以下文章

guid的值为null如何在C#反序列化

如何将具有固定模式的值数组反序列化为强类型数据类?

如何从 ASP.NET 中的 json 反序列化基本类型(System.Runtime.Serialization.Json)

如何根据json中的属性编写jackson反序列化器

如何检查 MySQL JSON 列是不是包含 laravel 中的值?

当您没有类型时,如何在 .NET 中反序列化 JSON 字符串