I am responsible for maintaining a game system where users persist JSON serialized POCOs in a local cache to preserve state of, e.g., a Character
.
The newest version of the code has changed the data model of these serialized objects. In particular, a new interface was created. This is creating issues when deserializing old copies of characters into the new code. I am attempting to resolve these with custom converters, but I'm running into trouble.
old, serialized version:
public class Character{
public Skill Parent {get;set;}
public Dictionary<string,Skill} Skills {get;set;}
}
public class Skill {
//normal stuff here.
}
new version:
public class Character{
[JsonProperty, JsonConverter(typeof(ConcreteTypeConverter<Dictionary<string,Skill>>))]
public Dictionary<string,ISkill} Skills {get;set;}
}
public class Skill:ISkill {
//normal stuff here.
}
public interface ISkill{
//stuff that all skill-like things have here
}
I have further defined a custom converter class (having read this and this,
but i'm still running into trouble deserializing collections.
public class Extensions
{
//a lot of serializer extensions here including the Deserialize method
private static readonly CustomSerializationBinder Binder = new CustomSerializationBinder();
private static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
TypeNameHandling = TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
Binder = Binder,
};
}
public class CustomSerializationBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
return base.BindToType(assemblyName, typeName);
}
}
public class ConcreteTypeConverter<T> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
serializer.Serialize(writer,value); // serialization isnt't the problem.
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (typeof (T)==typeof(Dictionary<string,Skill>))
{
var retVal = new object();
if (reader.TokenType == JsonToken.StartObject)
{
T instance = (T)serializer.Deserialize(reader, typeof(T)); //crashes here
retVal = new List<T>() { instance };
return retVal;
}
}
return serializer.Deserialize<T>(reader);
}
public override bool CanConvert(Type objectType)
{
return true; // kind of a hack
}
}
So i have an old Dictionary<string,Skill>
and I can't cast that to Dictionary<string,ISkill>
in any code-path that I can see. How should I resolve this?