Reputation: 45155
I have a class on the C# end that looks something like this:
[DataContract]
public class MyObject
{
[DataMember]
public SomeEnum FooType { get; set; }
[DataMember]
public FooBase MyFoo { get; set; }
}
Where, basically, the value in the property FooType
should tell you what specific type derived from FooBase
is present in the property MyFoo
.
Now if I just wanted to deserialize a object derived from FooBase
I could just do something like:
var myFoo = JsonConvert.DeserializeObject(myJsonString, typeof(FooDerived)) as FooDerived;
But how do I deserialize a MyObject
where the FooBase
object is nested and the information about what type it is can only be determined by partially deserializing the object first?
I'm thinking this is going to need a custom converter derived from JsonConverter, but I'm not entirely sure how to make ReadJson
work here.
Something like this?
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var result = new MyObject();
while(reader.Read())
{
if(reader.TokenType == JsonToken.PropertyName)
{
var prop = reader.Value as string;
if (prop == "FooType")
{
reader.Read();
result.FooType = (SomeEnum)reader.ReadAsInt32(); // or something like that
}
if (prop == "MyFoo")
{
reader.Read();
// now the reader.TokenType should be StartObject, but I can't
// deserialize the object because I don't know what type it is
// I might not have read "FooType" yet
// So I really need to pull this whole sub object out as a string
// and deserialize it later???
}
}
}
return result;
}
Upvotes: 2
Views: 2799
Reputation: 45155
Using this answer as inspiration: https://stackoverflow.com/a/19308474/1250301
I came up with something like this:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObj = JObject.Load(reader);
var foo = jObj["MyFoo"];
var result = new MyObject();
result.FooType = jObj["FooType"].ToObject<SomeEnum>();
switch (result.FooType)
{
case SomeEnum.Value1:
result.MyFoo = foo.ToObject<FooType1>();
break;
case SomeEnum.Value2:
result.MyFoo = foo.ToObject<FooType2>();
break;
case SomeEnum.Value3:
result.MyFoo = foo.ToObject<FooType3>();
break;
default:
throw new Exception("Unknown FooType");
}
return result;
}
The only problem here is that if I add new properties to the parent object, I'm going to need to manually map them. I thought I might be able to just do something like:
var parent = jObj.ToObject<MyObject>();
And then fill in the MyFoo
object, but this will just end up calling ReadJson
again.
Upvotes: 3
Reputation: 1438
I believe you can use Json.Linq
to accomplish this. I am not in front of a computer to test this but I believe its something like:
string fooTypeJson = JObject.Parse(myJsonString).SelectToken("FooType").ToString();
FooType fooType = reader.DeserializeObject<FooType>(fooTypeJson);
Upvotes: 2