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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…