加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 反序列化子类中的匿名顶级数组

发布时间:2020-12-16 02:02:15 所属栏目:百科 来源:网络整理
导读:我有一个 JSON响应,包含在外部数组中,如下所示: [ { "type": "a" },{ "type": "b","id": 1 },{ "type": "c","name": "somename" }] 我试图将此转换为对象,如下所示: class LoginOptions{ public IListILoginOption Options { get; set; }}interface ILogin
我有一个 JSON响应,包含在外部数组中,如下所示:

[
  {
    "type": "a"
  },{
    "type": "b","id": 1
  },{
    "type": "c","name": "somename"
  }
]

我试图将此转换为对象,如下所示:

class LoginOptions
{
    public IList<ILoginOption> Options { get; set; }
}

interface ILoginOption
{
    [JsonProperty("type")]
    LoginType LoginType { get; }
}

class LoginOptionA : ILoginOption{
    public LoginType LoginType
    {
        get { return LoginType.A; }
    }
}

class LoginOptionB : ILoginOption{
    public LoginType LoginType
    {
        get { return LoginType.B; }
    }

    [JsonProperty("id")]
    public int Id { get; set; }
}

class LoginOptionC : ILoginOption{
    public LoginType LoginType
    {
        get { return LoginType.C; }
    }

    [JsonProperty("name")]
    public string Name { get; set; }
}

导致此异常的原因是:

Cannot deserialize the current JSON array (e.g. [1,2,3]) into type ‘Library.Models.Domain.LoginOptions’ because the type requires a JSON object (e.g. {“name”:”value”}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {“name”:”value”}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection,IList) like List that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.

我宁愿不在我的LoginOptions类中实现一个集合,因为当我应该能够将它存储在字段中时,这将是太多的开销.使用[JsonArray]属性返回无法创建和填充列表类型Library.Models.Domain.LoginOptions.

我发现的大多数资源都处理顶部数组的{“name”:“value”}对,而不是匿名数组.我该如何反序化呢?

我相应地改变了我的代码:

public sealed class LoginOptions
{    
    [JsonConverter(typeof(LoginOptionConverter))]
    public IList<ILoginOption> Options { get; set; }
}

我的呼叫调度程序解析JSON的地方:

private List<ILoginOption> DeserializeObject<List<ILoginOption>>(Stream stream)
{
   using (StreamReader sr = new StreamReader(stream))
   using (JsonReader reader = new JsonTextReader(sr))
   {
       return new JsonSerializer().Deserialize<List<ILoginOption>>(reader);
   }
}

和这样的自定义转换器:

internal class LoginOptionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ILoginOption);
    }

    public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
    {
        var item = JObject.Load(reader);
        var data = item["type"].Value<string>();

        if (data == "UsernamePassword")
        {
            return item.ToObject<LoginOptionA>();
        }

        if (data == "Saml")
        {
            return item.ToObject<LoginOptionB>();
        }

        if (data == "Crm")
        {
            return item.ToObject<LoginOptionC>();
        }

        throw new ArgumentException("Invalid JSON response");
    }
}

这会引发错误

Could not create an instance of type Library.Models.Domain.ILoginOption. Type is an interface or abstract class and cannot be instantiated.

运用

new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects
};

建议here没有什么区别.

请注意,在将其放入自定义转换器之前会抛出此错误:创建JsonSerializer时会抛出此错误.

实例化发生在这里:

var settings = new JsonSerializerSettings
{
     TypeNameHandling = TypeNameHandling.Objects
};

using (StreamReader sr = new StreamReader(stream))
using (JsonReader reader = new JsonTextReader(sr))
{
    return JsonSerializer.Create(settings).Deserialize<List<ILoginOption>>(reader);
}

解决方法

由于JSON中的顶级是一个数组,因此您应该直接反序列化为一个列表.不需要包装类来保存列表.

List<ILoginOption> loginOptions = 
                   JsonConvert.DeserializeObject<List<ILoginOption>>(json);

现在,因为你的列表将包含几种不同类型的ILoginObjects,Json.Net将不知道要创建哪些,因为它反序列化列表.为此你需要一个JsonConverter. This answer显示了如何创建转换器来处理这个问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读