问题描述
我有一个 JSON 数组,其中包含具有不同属性的不同类型的对象.其中一个属性称为类型",并确定数组项的类型.这是我的数据示例:
I have a JSON-array containing objects of different types with different properties. One of the properties is called "type" and determines the type of the array item. Here is an example of my data:
[{
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 实现,我定义了一组类:一个基类和几个子类(具有复杂的层次结构,具有 4 个代").这里只是这些类的一个小例子:
To map those objects to my .Net implementation I define a set of classes: one base class and several child classes (with a complex hierarchy, having 4 "generations"). Here is just a small example of these classes:
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<TToken> Tokens { get; set; }
}
我想要达到的是能够将这个数组反序列化为一个协变的泛型列表,声明为:
What I want to reach is to be able to deserialize this array into a covariant generic list, declared as:
List<TExpression> myexpressions = JsonConvert.DeserializeObject<List<TExpression>>(aststring);
此列表应包含从 TExpression 继承的适当子类的实例,因此我可以稍后在我的代码中使用以下代码:
This list should contain the instances of appropriate child classes inheriting from TExpression, so I can use the following code later in my code:
foreach(TExpression t in myexpressions)
{
if (t is TComment) dosomething;
if (t is TTokenSequence) dosomethingelse;
}
如何使用 JSON.NET 访问它?
How can I reach it using JSON.NET?
推荐答案
这里是一个使用 CustomCreationConverter 的例子.
Here is an example using CustomCreationConverter.
public class JsonItemConverter : Newtonsoft.Json.Converters.CustomCreationConverter<Item>
{
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<List<Item>>(json, new JsonItemConverter());
foreach (var r in result)
{
// r is an instance of Item not StringItem or IntItem
Console.WriteLine("got " + r.ToString());
}
}
}
这篇关于将异构 JSON 数组反序列化为协变列表<>使用 Json.NET的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!