[英]How to deserialize a JSON array of elements with different types and varying number of elements?
我正在處理一個JSON
數組,其中每個元素具有不同的類型,由type
屬性指示。 可以有多個相同類型的元素,並且元素的數量事先未知。 那是:
[
{
'abc': '0',
'type': 'a'
},
{
'cde': '10',
'type: 'b'
},
{
'abc': '20'
'type': 'a'
}
]
我需要將這樣的數組反序列化為List<A>
和List<B>
。
我查看了Json.NET
文檔,但不確定將什么用於此任務是一個好的策略或功能。 任何指針將不勝感激。
假設您的類型都是已知的,則可以將所有元素反序列化為JObject
並使用linq將初始數組分成多個列表。
您可以聲明dbc建議的抽象基本類型,而不是使用List<JObject>
,然后實現自定義JsonConverter。
無論哪種情況,如果您想要每種子類型的單獨列表,則需要迭代將超類型轉換為子類型的初始數組。
定義您的類型:
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;
}
}
最后,您反序列化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屬性是您類型的完全限定名稱時,才可以在定制創建轉換器中使用此名稱:
protected override BaseClass Create(Type objectType, JObject jObject)
{
string type = jObject["type"].Value<string>();
return (BaseClass)Activator.CreateInstance(Type.GetType(type));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.