I am serializing using Json.NET, but the resulting string ends up way too long, because it includes a ton of surplus info about the assembly that I have no use for.
For example, here is what I'm getting for one of the types:
"Assets.Logic.CompGroundType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null": {
"$type": "Assets.Logic.CompGroundType, Assembly-CSharp",
"GroundType": 1,
"EntityID": 1,
"<GroundType>k__BackingField": 1
}
"GroundType" is an enum, and "EntityID" is int.
Here is my desired result:
"Assets.Logic.CompGroundType" : {
"$type": "Assets.Logic.CompGroundType",
"GroundType": 1,
"EntityID": 1,
"<GroundType>k__BackingField": 1
}
If it's possible, I would also like to remove the "$type" field while still correctly deserializing inherited types (I'm not sure why it's necessary, since that info is duplicated from one line above, but if I remove it by setting TypeNameHandling.None, I get deserialization errors for child types). I am also not sure what the last field (k__BackingField) is for.
If it's possible, I would want to reduce it even further, to:
"Assets.Logic.CompGroundType" : {
"GroundType": 1,
"EntityID": 1,
}
I understand it's possible to manually customize the serialization scheme for each type in Json.Net, but I have hundreds of types, and so I would like to do it automatically through some global setting.
I tried changing "FormatterAssemblyStyle", but there is no option for "None" there, only "Simple" or "Full", and I'm already using "Simple".
Thanks in advance for any help.
Edit:
It's important to note that the types are keys in a dictionary. That's why the type appears twice (in the first and second row of the first example).
After implementing a custom SerializationBinder, I was able to reduce the length of the "$type" field, but not the Dictionary key field. Now I get the following:
"componentDict": {
"Assets.Logic.CompGroundType, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null": {
"$type": "Assets.Logic.CompGroundType",
"GroundType": 1,
"EntityID": 1,
"<GroundType>k__BackingField": 1
}
}
Edit 2:
The code I'm trying to serialize is an entity component system. I'll try to provide a detailed example with code samples.
All components (including CompGroundType
above) inherit from the following abstract class:
abstract class Component
{
public int EntityID { get; private set; }
protected Component(int EntityID)
{
this.EntityID = EntityID;
}
}
The issue I'm encountering is in the serialization of the Entity
class' componentDict
:
class Entity
{
readonly public int id;
private Dictionary<Type, Component> componentDict = new Dictionary<Type, Component>();
[JsonConstructor]
private Entity(Dictionary<Type, Component> componentDict, int id)
{
this.id = id;
this.componentDict = componentDict;
}
}
componentDict
contains all the components attached to the entity. In each entry <Type, Component>
, the type of the value is equal to the key.
I am doing the serialization recursively, using the following JsonSerializerSettings
:
JsonSerializerSettings serializerSettings = new JsonSerializerSettings()
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new MyContractResolver(),
TypeNameHandling = TypeNameHandling.Auto,
SerializationBinder = new TypesWithNoAssmeblyInfoBinder(),
Formatting = Formatting.Indented
}
Where MyContractResolver
is identical to the one form this answer.
TypesWithNoAssmeblyInfoBinder
does the change from edit 1:
private class TypesWithNoAssmeblyInfoBinder : ISerializationBinder
{
public Type BindToType(string assemblyName, string typeName)
{
return Type.GetType(typeName);
}
public void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = serializedType.FullName;
}
}
The serialization itself is done as follows:
var jsonSerializer = JsonSerializer.Create(serializerSettings);
using (FileStream zippedFile = new FileStream(Application.persistentDataPath + fileName, FileMode.Create))
{
using (GZipStream archive = new GZipStream(zippedFile, CompressionLevel.Fastest))
{
using (StreamWriter sw = new StreamWriter(archive))
{
jsonSerializer.Serialize(sw, savedData);
}
}
}
Edit 4:
The CompGroundType
class (an example of a finished component):
class CompGroundType : Component
{
public enum Type {Grass, Rock};
public Type GroundType { get; private set; }
[JsonConstructor]
private CompGroundType(Type groundType, int entityID) : base(entityID)
{
this.GroundType = groundType;
}
}