Дезаминирование гетерогенного массива JSON в ковариантный список с использованием JSON.NET

У меня есть JSON-массив, содержащий объекты разных типов с разными свойствами. Одно из свойств называется «тип» и определяет тип элемента массива. Вот пример моих данных:

[{ type : "comment", text : "xxxx" }, { type : "code", tokens : [{ type : "ref", data : "m" }, { type : "operator", data : "e" } ] }, { type : "for", boundLocal : { type : "local", name : "i", kind : "Number" }, upperBound : { type : "ref", tokens : [{ type : "operator", data : "3" }, { type : "operator", data : "0" } ] }, body : [{ type : "code", tokens : [{ type : "ref", data : "x" } ] }, { type : "code", tokens : [{ type : "ref", data : "y" } } ] ] ] 

Чтобы сопоставить эти объекты с моей .Net-реализацией, я определяю набор classов: один базовый class и несколько дочерних classов (со сложной иерархией, имеющей 4 «поколения»). Вот лишь небольшой пример этих classов:

 public abstract class TExpression { [JsonProperty("type")] public string Type { get; set; } } public class TComment : TExpression { [JsonProperty("text")] public string Text { get; set; } } public class TTokenSequence : TExpression { [JsonProperty("tokens")] public List Tokens { get; set; } } 

Я хочу достичь десериализации этого массива в ковариантный общий список, объявленный как:

 List myexpressions = JsonConvert.DeserializeObject<List>(aststring); 

Этот список должен содержать экземпляры соответствующих дочерних classов, наследующих от TExpression, поэтому я могу использовать следующий код в моем коде:

 foreach(TExpression t in myexpressions) { if (t is TComment) dosomething; if (t is TTokenSequence) dosomethingelse; } 

Как я могу связаться с ним с помощью JSON.NET?

Вот пример использования CustomCreationConverter.

 public class JsonItemConverter : Newtonsoft.Json.Converters.CustomCreationConverter { public override Item Create(Type objectType) { throw new NotImplementedException(); } public Item Create(Type objectType, JObject jObject) { var type = (string)jObject.Property("valueType"); switch (type) { case "int": return new IntItem(); case "string": return new StringItem(); } throw new ApplicationException(String.Format("The given vehicle type {0} is not supported!", type)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // Load JObject from stream JObject jObject = JObject.Load(reader); // Create target object based on JObject var target = Create(objectType, jObject); // Populate the object properties serializer.Populate(jObject.CreateReader(), target); return target; } } public abstract class Item { public string ValueType { get; set; } [JsonProperty("valueTypeId")] public int ValueTypeId { get; set; } [JsonProperty("name")] public string Name { get; set; } public new virtual string ToString() { return "Base object, we dont' want base created ValueType=" + this.ValueType + "; " + "name: " + Name; } } public class StringItem : Item { [JsonProperty("value")] public string Value { get; set; } [JsonProperty("numberChars")] public int NumberCharacters { get; set; } public override string ToString() { return "StringItem object ValueType=" + this.ValueType + ", Value=" + this.Value + "; " + "Num Chars= " + NumberCharacters; } } public class IntItem : Item { [JsonProperty("value")] public int Value { get; set; } public override string ToString() { return "IntItem object ValueType=" + this.ValueType + ", Value=" + this.Value; } } class Program { static void Main(string[] args) { // json string var json = "[{\"value\":5,\"valueType\":\"int\",\"valueTypeId\":1,\"name\":\"numberOfDups\"},{\"value\":\"some thing\",\"valueType\":\"string\",\"valueTypeId\":1,\"name\":\"a\",\"numberChars\":11},{\"value\":2,\"valueType\":\"int\",\"valueTypeId\":2,\"name\":\"b\"}]"; // The above is deserialized into a list of Items, instead of a hetrogenous list of // IntItem and StringItem var result = JsonConvert.DeserializeObject>(json, new JsonItemConverter()); foreach (var r in result) { // r is an instance of Item not StringItem or IntItem Console.WriteLine("got " + r.ToString()); } } } 

CustomCreationConverter должен иметь возможность справиться с этим.

Он также может быть реализован с помощью JsonSubTypes декларативным способом:

 [JsonConverter(typeof(JsonSubtypes), "valueType")] [JsonSubtypes.KnownSubType(typeof(IntItem), "int")] [JsonSubtypes.KnownSubType(typeof(StringItem), "string")] public abstract class Item { public string ValueType { get; set; } [JsonProperty("valueTypeId")] public int ValueTypeId { get; set; } [JsonProperty("name")] public string Name { get; set; } public override string ToString() { return "Base object, we dont' want base created ValueType=" + this.ValueType + "; " + "name: " + Name; } } public class StringItem : Item { [JsonProperty("value")] public string Value { get; set; } [JsonProperty("numberChars")] public int NumberCharacters { get; set; } public override string ToString() { return "StringItem object ValueType=" + this.ValueType + ", Value=" + this.Value + "; " + "Num Chars= " + NumberCharacters; } } public class IntItem : Item { [JsonProperty("value")] public int Value { get; set; } public override string ToString() { return "IntItem object ValueType=" + this.ValueType + ", Value=" + this.Value; } } [TestMethod] public void Demo() { // json string var json = "[{\"value\":5,\"valueType\":\"int\",\"valueTypeId\":1,\"name\":\"numberOfDups\"}," + "{\"value\":\"some thing\",\"valueType\":\"string\",\"valueTypeId\":1,\"name\":\"a\",\"numberChars\":11}," + "{\"value\":2,\"valueType\":\"int\",\"valueTypeId\":2,\"name\":\"b\"}]"; var result = JsonConvert.DeserializeObject>(json); Assert.AreEqual("IntItem object ValueType=int, Value=5", result[0].ToString()); Assert.AreEqual("StringItem object ValueType=string, Value=some thing; Num Chars= 11", result[1].ToString()); Assert.AreEqual("IntItem object ValueType=int, Value=2", result[2].ToString()); } 
  • Разбор большого json-файла в .NET.
  • Как реализовать пользовательский JsonConverter в JSON.NET для десериализации списка объектов базового classа?
  • Json.NET Отключить десериализацию в DateTime
  • Отключить JSON в существующий объект (Java)
  • Дезерминирование полиморфных типов с jacksonом
  • Json.NET: десериализация вложенных словарей
  • Дессериализация данных JSON на C # с использованием JSON.NET
  • Библиотека Jackson JSON: как создать экземпляр classа, содержащего абстрактные поля
  • Уничтожить XML-объект с помощью динамического
  • Десериализация JSON с использованием JSon.NET с динамическими данными
  • Давайте будем гением компьютера.