问题
I am dealing with a JSON
array, where each element is of a different type, indicated by a type
attribute. There can be more than one element of the same type, and the number of elements is not known beforehand. That is:
[
{
'abc': '0',
'type': 'a'
},
{
'cde': '10',
'type: 'b'
},
{
'abc': '20'
'type': 'a'
}
]
I need to deserialize such an array into a List<A>
and List<B>
.
I looked into Json.NET
documentation but I am not sure what would be a good strategy or feature to use for this task. Any pointers would be appreciated.
回答1:
Assuming your types are all known before hand you can deserialize all elements to JObject
and use linq to separate the initial array into multiple lists.
Instead of using List<JObject>
, you could declare an abstract base type as dbc suggests then implement a custom JsonConverter.
In either case if you want separate lists of each sub type you will need to iterate over your initial array converting the super type to sub type.
Define your types:
class A
{
public int abc { get; set; }
}
class B
{
public int cde { get; set; }
}
Then deserialize your base array, and use linq to split into two separate lists.
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();
回答2:
Re-elaborating answers given here and here, and using a base class as stated by dbc, you can obtain the required result.
First, define the types:
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; }
}
Then, define the custom creation converter:
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;
}
}
Finally, you deserialize your json and obtain the wanted lists:
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();
If and only if the type attribute is the fully qualified name of your type, you can use this in the custom creation converter:
protected override BaseClass Create(Type objectType, JObject jObject)
{
string type = jObject["type"].Value<string>();
return (BaseClass)Activator.CreateInstance(Type.GetType(type));
}
来源:https://stackoverflow.com/questions/54027333/how-to-deserialize-a-json-array-of-elements-with-different-types-and-varying-num