C# 如何反序列化具有不同类型和不同数量元素的JSON元素数组?
我正在处理一个JSON数组,其中每个元素都是不同的类型,由一个type属性表示。同一类型可以有多个元素,并且元素的数量事先不知道。即:C# 如何反序列化具有不同类型和不同数量元素的JSON元素数组?,c#,.net,json.net,C#,.net,Json.net,我正在处理一个JSON数组,其中每个元素都是不同的类型,由一个type属性表示。同一类型可以有多个元素,并且元素的数量事先不知道。即: [ { 'abc': '0', 'type': 'a' }, { 'cde': '10', 'type: 'b' }, { 'abc': '20' 'type': 'a' } ] 我需要将这样一个数组反序列化为一个列表和一个列表 我查阅了Json.NET文档,但我不确定在这项任务中使用什么
[
{
'abc': '0',
'type': 'a'
},
{
'cde': '10',
'type: 'b'
},
{
'abc': '20'
'type': 'a'
}
]
我需要将这样一个数组反序列化为一个列表和一个列表
我查阅了Json.NET文档,但我不确定在这项任务中使用什么策略或功能是好的。任何指针都可以。假设您的类型都是已知的,您可以将所有元素反序列化到JObject,并使用linq将初始数组分隔为多个列表 您可以按照dbc的建议声明一个抽象基类型,然后实现一个自定义JsonConverter,而不是使用List 在任何一种情况下,如果您想要每个子类型的单独列表,则需要迭代初始数组,将超级类型转换为子类型 定义您的类型:
class A
{
public int abc { get; set; }
}
class B
{
public int cde { get; set; }
}
然后反序列化基本数组,并使用linq将其拆分为两个单独的列表
string json = @"[
{
'abc': '0',
'type': 'a'
},
{
'cde': '10',
'type': 'b'
},
{
'abc': '20',
'type': 'a'
}
]";
List<JObject> objs = JsonConvert.DeserializeObject<List<JObject>>(json);
List<A> objectsA = objs.Where(d => d["type"].ToString() == "a").Select(d => d.ToObject<A>()).ToList();
List<B> objectsB = objs.Where(d => d["type"].ToString() == "b").Select(d => d.ToObject<B>()).ToList();
重新解释给出的答案,并使用dbc所述的基类,可以获得所需的结果 首先,定义类型:
class BaseClass
{
[JsonProperty("type")]
public string EntityType
{ get; set; }
}
class A : BaseClass
{
public int abc { get; set; }
}
class B : BaseClass
{
public int cde { get; set; }
}
然后,定义自定义创建转换器:
class BaseClassConverter : JsonCreationConverter<BaseClass>
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Implement this if you need to serialize the object too
throw new NotImplementedException();
}
protected override BaseClass Create(Type objectType, JObject jObject)
{
if (jObject["type"].Value<string>() == "a")
{
return new A();
}
else
{
return new B();
}
}
}
public abstract class JsonCreationConverter<T> : JsonConverter
{
/// <summary>
/// Create an instance of objectType, based properties in the JSON object
/// </summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">
/// contents of JSON object that will be deserialized
/// </param>
/// <returns></returns>
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite
{
get { return false; }
}
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
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
protected override BaseClass Create(Type objectType, JObject jObject)
{
string type = jObject["type"].Value<string>();
return (BaseClass)Activator.CreateInstance(Type.GetType(type));
}
最后,将json反序列化并获得通缉名单:
string json = @"[
{
'abc': '0',
'type': 'a'
},
{
'cde': '10',
'type': 'b'
},
{
'abc': '20',
'type': 'a'
}
]";
List<BaseClass> objects = JsonConvert.DeserializeObject<List<BaseClass>>(json, new BaseClassConverter());
List<A> aObjects = objects.Where(t => t.GetType() == typeof(A)).Select(o => (A)o).ToList();
List<B> bObjects = objects.Where(t => t.GetType() == typeof(B)).Select(o => (B)o).ToList();
如果且仅当type属性是类型的完全限定名时,您可以在自定义创建转换器中使用该名称:
class BaseClassConverter : JsonCreationConverter<BaseClass>
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Implement this if you need to serialize the object too
throw new NotImplementedException();
}
protected override BaseClass Create(Type objectType, JObject jObject)
{
if (jObject["type"].Value<string>() == "a")
{
return new A();
}
else
{
return new B();
}
}
}
public abstract class JsonCreationConverter<T> : JsonConverter
{
/// <summary>
/// Create an instance of objectType, based properties in the JSON object
/// </summary>
/// <param name="objectType">type of object expected</param>
/// <param name="jObject">
/// contents of JSON object that will be deserialized
/// </param>
/// <returns></returns>
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite
{
get { return false; }
}
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
T target = Create(objectType, jObject);
// Populate the object properties
serializer.Populate(jObject.CreateReader(), target);
return target;
}
}
protected override BaseClass Create(Type objectType, JObject jObject)
{
string type = jObject["type"].Value<string>();
return (BaseClass)Activator.CreateInstance(Type.GetType(type));
}
看起来这好像被错误地标记为重复?引用的重复问题与类型不同的对象数组无关。@Neil,我同意。我确实更改了问题的标题以使其更清楚,我希望这会有所帮助。为什么不反序列化到列表中呢?如果您这样做,它将是和/或的副本。必须反序列化为两个顶级列表意味着两次通过JSON。或者,如果“type”属性直接对应于.Net类型,则可以使用。