Json.NET 无法将索引 属性 反序列化为数组

Json.NET can't Deserialize Indexed Property into Array

这有点夸张,但它是一个真实世界的例子,但它是蓬松的。我们有一个列表中有多个 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; }
    }
}

Json.Net 中没有一个属性可以直接将您的蓬松对象转换为列表,但您可以自定义 JsonConverter 来轻松完成此操作,然后装饰您的 Data class 带有一个属性告诉 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 class 上放置一个 [JsonConverter] 属性,如下所示:

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

当您重新运行测试代码时,它应该会像您描述的那样工作。

你可以试试这个。

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