将JSON反序列化为具有多态类型的容器

时间:2014-04-17 00:53:09

标签: c# json json.net

我有一个只有几个多态类型成员的类。它不是像List这样的集合意义上的容器,只是一个类。

public class Stuff {
    public BaseClassA MyA;
    public BaseClassB MyB;
}

当然,BaseClassA和BaseClassB可以有各种子类。我需要能够将这些序列化和反序列化为JSON。我一直在使用Json.NET。

我想避免包含类型信息。对于简单的情况,让我们说每当我想要反序列化时,我就会知道MyA和MyB的具体类是什么。但是,如何告知Json.NET我的知识?我认为JsonConvert.DeserializeObject<Stuff>将不起作用,因为它将尝试创建BaseClassA和BaseClassB的实例,而不是MyA和MyB最初的子类。

我能想到几个答案。我正在寻找更好的答案。为了清楚我要求的内容,我将举出一两个我能想到的例子。

我可以在Stuff

上使用通用静态方法
public static Stuff DeserializeMyStuff<TA, TB>(string json) where TA: BaseClassA where TB: BaseClassB
{
    JsonSerializer serializer = new JsonSerializer();
    JObject obj = JObject.Parse(json);
    BaseClassA a = serializer.Deserialize<TA>(obj["MyA"].CreateReader());
    BaseClassB b = serializer.Deserialize<TB>(obj["MyB"].CreateReader());
    return new Stuff { MyA = a, MyB = b };
}

我可以使用未初始化的具体类型实例预填充Stuff,并使用已经存在的类型的自定义转换器。这样做的好处是Stuff对象可以是更大的东西的一部分,你可以序列化整个blob。

Stuff myStuff = new Stuff { MyA = new SpecificA(), MyB = new SpecificB() };
JsonConvert.PopulateObject(json, myStuff);

[JsonConverter(typeof(StuffConverter)]
public class Stuff {
    ...

public class StuffConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        BaseClassA a = serializer.Deserialize(obj["MyA"].CreateReader(), ((Stuff)existingValue).MyA.Type);
        BaseClassB b = serializer.Deserialize(obj["MyB"].CreateReader(), ((Stuff)existingValue).MyB.Type);
        return new Stuff { MyA = a, MyB = b };
    }
}

我可以通过使用真实数据的访问器定义Stuff来懒惰地反序列化

public class Stuff {
    public JToken JsonA;
    public JToken JsonB;

    public BaseClassA GetMyA<T>() where T: BaseClassA { ... }
    public BaseClassB GetMyB<T>() where T: BaseClassB { ... }
}

好的,现在对于更棘手的部分。有时当我反序列化时,我只会知道MyA的子类,而不是MyB。在这种情况下,我也不希望访问MyB,但如果我再次序列化,我确实希望保留它。第三种方法可以正常工作,第二种方法可能会被修改以处理它。

以前有人遇到过这个问题,并找到了一个很好的解决方案吗?

0 个答案:

没有答案