【问题标题】:Json.NET can't Deserialize Indexed Property into ArrayJson.NET 无法将索引属性反序列化为数组
【发布时间】:2015-11-08 15:16:06
【问题描述】:

这是一个延伸,但它是一个真实世界的例子,但还很模糊。我们有一个 Data 节点,列表中有多个 Fluff 对象。它们根据它们在列表中的索引来命名,例如:{ Fluff_0, Fluff_1, ..., Fluff_n }

当我反序列化这个对象时,我希望它被反序列化为 List<Fluff>

有没有办法用 JsonPropertyAttributes 来装饰它,这样我就可以在 Data 对象中获得 Fluff 对象的有序通用列表(或其他集合)?

[TestFixture]
public class FluffDeserializationTests
{
    [Test]
    public void FluffDeserialization()
    {
        var json = "{\"Data\": { \"Fluff_0\": {\"ID\": \"abc\"}, \"Fluff_1\": { \"ID\": \"abd\" } } }";
        var result = JsonConvert.DeserializeObject<Fluff>(json);
        Assert.That(result.Data.Things != null);
        Assert.That(result.Data.Things.Count, Is.EqualTo(2));
        Assert.That(result.Data.Things[0].ID, Is.EqualTo("abc"));
        Assert.That(result.Data.Things[1].ID, Is.EqualTo("abd"));
    }


    public class Fluff
    {
        public Data Data { get; set; }
    }

    public class Data
    {
        public List<Thing> Things { get; set; }
    }

    public class Thing
    {
        public string ID { get; set; }
    }
}

【问题讨论】:

  • 您的"Data" 容器是一个JSON 对象,标准定义为an unordered set of name/value pairs。那么,您希望列表在反序列化后的顺序是什么?
  • 按照它们在 json 字符串 @dbc 中出现的顺序。

标签: c# json json.net json-deserialization


【解决方案1】:

Json.Net 中没有属性可以直接将您的蓬松对象转换为列表,但是您可以制作自定义JsonConverter 来做到这一点而不会太麻烦,然后用属性装饰您的Data 类告诉 Json.Net 使用转换器。

这是转换器的外观。请注意,如果在Fluff_n 键的序列中碰巧有任何间隙,此代码仍将在结果列表中保持它们的相对顺序,但不会保留间隙。我猜这不会是一个问题,但仅供参考。

class FluffDataConverter : JsonConverter
{
    readonly int PrefixLength = "Fluff_".Length;

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(Data));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        List<Thing> things = jo.Properties()
                               .OrderBy(p => int.Parse(p.Name.Substring(PrefixLength)))
                               .Select(p => p.Value.ToObject<Thing>())
                               .ToList();
        return new Data { Things = things };
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

要使用此转换器,只需在您的 Data 类上放置一个 [JsonConverter] 属性,如下所示:

[JsonConverter(typeof(FluffDataConverter))]
public class Data
{
    public List<Thing> Things { get; set; }
}

当您重新运行测试代码时,它应该可以按照您的描述工作。

【讨论】:

  • 传奇,绝对是我所追求的!我最终解决它的方法是遍历所有内部对象,并使我的转换器通用,不幸的是我无法在这里发布该评论,因为我无法让它格式化代码:)。你的解决方案是第一个进来的,所以我会给你荣誉!谢谢!
  • 没问题;很高兴能帮助你。仅供参考,如果您想分享您的最终解决方案,您可以发布自己问题的答案。评论是本网站上的“二等公民”,因此有意限制您在其中添加的内容。
【解决方案2】:

你可以试试这个。

var things = new List<Thing>();
var json = "{\"Data\": { \"Fluff_0\": {\"ID\": \"abc\"}, \"Fluff_1\": { \"ID\": \"abd\" } } }";
JObject jObject = JObject.Parse(json);
var data = (JObject)jObject["Data"];  
var prop = data.Properties().Where(p => p.Name.Contains("Fluff")).Count();
if (prop > 0)
  for (int i = 0; i < prop; i++)
    things.Add(new Thing { ID = (string)((JObject)data["Fluff_" + i])["ID"]});  //please check if get null value

【讨论】:

  • 问题是很难做到通用。在我使用的 API 中有很多这种生成列表的方式的示例,所以我真的需要为此使用转换器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-13
  • 2012-03-16
  • 2023-03-12
  • 2014-08-22
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
相关资源
最近更新 更多