开发者

Deserializing ambiguous json

public abstract class A {
    public string Foo{ get; set; }
}

public class B : A {
    public string Marco{ get; set; }
}

public class C : A {
    public string Las{ get; set; }
}

public class D : A {
    public string Las{ get; set; }
}

public class SerializeMe {
    [XmlElement("b", typeof(B))]
    [XmlElement("c", typeof(C))]
    [XmlElement("d", typeof(D))]
    public A[] serializeProp { get; set; }
}

SerializeMe me = new SerializeMe();
me.serializeProp = new A[]{
                           new B(){ Foo = "bar", Marco = "polo" },
                           new C(){ Foo = "bar", Las = "Vegas" },
                           new D(){ Foo = "bar", Las = "Vegas" }
                          };

The XmlElement attributes control xml serialization so this results in:

 <SerializeMe>
    <B><Foo>bar</Foo><Marco>polo</Marco></B>
    <C><Foo>bar</Foo><Las>Vegas</Las></C>
    <D><Foo>bar</Foo><Las>Vegas</Las></D>
 </SerializeMe>

And if I was to add similar attributes to deserialize into json (using Newtonsoft Json.Net library):

{[
    {"Foo":"bar", "Marco":"polo"},
    {"Foo":"bar", "Las":"Vegas"},
    {"Foo":"bar", "Las":"Vegas"}
]}

However, unlike the xml it doesn't contain details on the types, so it isn't apparent to me that it will correctly identify which class to deserialize into. Is there anyway of correctly deserializing using the existing json structure, or do I have to modify the json structure (and how best to do that).

I thought of overriding the serialization so that it produced the following format:

{[
    {"class":"B",
     "object":{"Foo":"bar", "Marco":"polo"}},
    {"class":"C",
     "object":{"Foo":"bar", "Las":"Vegas"}},
    {"class":"D",
开发者_Go百科     "object":{"Foo":"bar", "Las":"Vegas"}}
]}

Is there a better way?


You could leave out the nested "object"= and just use a string that's not a valid property name as class identifier:

{"Foo":"bar", "Marco":"polo", "$Class"="B"}

JSON.net has a TypeNameHandling feature built in, generated json looks like this:

{"$type":"Tests.MessageWrapper2, Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
"Headers":{"$type":"System.Collections.Hashtable, mscorlib, Version=2.0.0.0, Culture=neutral,PublicKeyToken=b77a5c561934e089","DeliverAt":"yesterday!"},
"Body":{"$type":"Tests.TestMessage1, Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null","Id":893239}
}

Note that if you're using TypeNameHandling the json can construct arbitrary types. So you might not want to deserialize json from an untrusted source.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜