将JSON中的嵌套对象反序列化为特定类型

时间:2014-07-29 17:47:22

标签: c# json serialization json.net

我在C#端上有一个类看起来像这样的课程:

[DataContract]
public class MyObject
{
    [DataMember]
    public SomeEnum FooType { get; set; }

    [DataMember]
    public FooBase MyFoo { get; set; }
}

基本上,属性FooType中的值应该告诉您属性FooBase中存在的MyFoo派生的特定类型。

现在,如果我只想反序列化从FooBase派生的对象,我可以执行以下操作:

var myFoo = JsonConvert.DeserializeObject(myJsonString, typeof(FooDerived)) as FooDerived;

但是如何反序列化嵌套MyObject对象的FooBase以及它的类型信息只能通过首先对对象进行部分反序列化来确定?

我认为这需要一个从JsonConverter派生的自定义转换器,但我不完全确定如何让ReadJson在这里工作。

这样的东西?

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;
}

2 个答案:

答案 0 :(得分:2)

将此答案用作灵感:https://stackoverflow.com/a/19308474/1250301

我想出了类似的东西:

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;
}

这里唯一的问题是,如果我向父对象添加新属性,我将需要手动映射它们。我想我可以做一些像:

var parent = jObj.ToObject<MyObject>(); 

然后填写MyFoo对象,但这最终会再次调用ReadJson

答案 1 :(得分:1)

我相信您可以使用Json.Linq来完成此任务。我不是在电脑前测试这个,但我相信它是这样的:

string fooTypeJson = JObject.Parse(myJsonString).SelectToken("FooType").ToString();
FooType fooType = reader.DeserializeObject<FooType>(fooTypeJson);