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