2

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;
}
Matt Burland
  • 44,552
  • 18
  • 99
  • 171
  • possible duplicate of [Deserializing polymorphic json classes without type information using json.net](http://stackoverflow.com/questions/19307752/deserializing-polymorphic-json-classes-without-type-information-using-json-net) – Brian Rogers Jul 30 '14 at 01:49
  • @BrianRogers: I don't think it's an exact duplicate (the polymorphic part here is nested which makes this a little trickier), but I think the answer there does give me a really good lead on solving the problem. If I had found that question first when searching, I probably wouldn't have needed to ask. – Matt Burland Jul 30 '14 at 12:48
  • Yep, that's what I thought too-- it was close enough to allow you to solve the problem. Glad you got it working. – Brian Rogers Jul 30 '14 at 14:19

2 Answers2

3

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.

Community
  • 1
  • 1
Matt Burland
  • 44,552
  • 18
  • 99
  • 171
2

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);
aaronmallen
  • 1,418
  • 1
  • 12
  • 29
  • The problem is that I can't quite figure out how to get hold of the original string once you are in `ReadJson`. I could try to handle it outside of the `JsonConverter`, but that seems like the wrong way to handle it. – Matt Burland Jul 29 '14 at 20:01
  • Oh you've already deserialized it into the parent object it looks like. so why don't you just call it from the parent object? `FooType fooType = myFoo.FooType`? – aaronmallen Jul 29 '14 at 20:04