Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
234 views
in Technique[技术] by (71.8m points)

.net - JSON serialization of array with polymorphic objects

Is it possible with .NET standard JavascriptSerializer/JsonDataContractSerializer or external parsers, to serialize objects array using a wrapper approach including the object type?

For example, to generate this JSON from a List:

[{ 'dog': { ...dog properties... } },
 { 'cat': { ...cat properties... } }]

instead of typical:

[{ ...dog properties... },
 { ...cat properties... }]

This is doable in Java with Jackson using JsonTypeInfo.As.WRAPPER_OBJECT attribute.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Json.NET has a neat solution for this. There is a setting that intelligently adds type information - declare it like this:

new JsonSerializer { TypeNameHandling = TypeNameHandling.Auto };

This will determine whether type embedding is required and add it where necessary. Lets say I had the following classes:

public class Message
{
    public object Body { get; set; }
}

public class Person
{
    public string Name { get; set; }
}

public class Manager : Person
{

}

public class Department
{
    private List<Person> _employees = new List<Person>();
    public List<Person> Employees { get { return _employees; } }
}

Notice the Message Body is of type object, and that Manager subclasses Person. If I serialize a Message with a Department Body that has a single Manager I get this:

{
    "Body":
    {
        "$type":"Department, MyAssembly",
        "Employees":[
            {
                "$type":"Manager, MyAssembly",
                "Name":"Tim"
            }]
    }
}

Notice how it's added the $type property to describe the Department and Manager types. If I now add a Person to the Employees list and change the Message Body to be of type Department like this:

public class Message
{
    public Department Body { get; set; }
}

then the Body type annotation is no longer needed and the new Person is not annotated - absence of annotation assumes the element instance is of the declared array type. The serialized format becomes:

{
    "Body":
    {
        "Employees":[
            {
                "$type":"Manager, MyAssembly",
                "Name":"Tim"
            },
            {
                "Name":"James"
            }]
    }
}

This is an efficient approach - type annotation is only added where required. While this is .NET specific, the approach is simple enough to handle that deserializers/message types on other platforms should be fairly easily extended to handle this.

I'd be reticent about using this in a public API though, as it is non-standard. In that case you'd want to avoid polymorphism, and make versioning and type information very explicit properties in the message.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...