We might need to expose some APIs to provide a way to (de-)serialize State. With Json.NET, it doesn't actually need any changes to the library, here's a quick and dirty implementation of a JsonConverter:
class StateJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (objectType.IsGenericType)
{
// field type definition for deserialization - the interface directly
if (objectType.GetGenericTypeDefinition() == typeof(State<>))
{
return true;
}
// run-time object type for serialization - the implementation
foreach (var iface in objectType.GetInterfaces())
{
if (iface.IsGenericType && iface.GetGenericTypeDefinition() == typeof(State<>))
{
return true;
}
}
}
return false;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
GetConverter(value.GetType()).WriteJson(writer, value, serializer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return GetConverter(objectType).ReadJson(reader, existingValue, serializer);
}
StateConverter GetConverter(Type stateType)
{
// TODO: cache converters
var rt = typeof(StateConverter<>).MakeGenericType(stateType.GetGenericArguments()[0]);
return (StateConverter)Activator.CreateInstance(rt, false);
}
}
abstract class StateConverter
{
public abstract void WriteJson(JsonWriter writer, object value, JsonSerializer serializer);
public abstract object ReadJson(JsonReader reader, object existingValue, JsonSerializer serializer);
}
class StateConverter<T> : StateConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
WriteJsonInternal(writer, (State<T>)value, serializer);
}
public override object ReadJson(JsonReader reader, object existingValue, JsonSerializer serializer)
{
return ReadJsonInternal(reader, existingValue, serializer);
}
void WriteJsonInternal(JsonWriter writer, State<T> state, JsonSerializer serializer)
{
serializer.Serialize(writer, state.Value);
}
State<T> ReadJsonInternal(JsonReader reader, object existingValue, JsonSerializer serializer)
{
var stateValue = serializer.Deserialize<T>(reader);
if (existingValue is State<T> existingState)
{
existingState.Value = stateValue;
return existingState;
}
return Observable.State(stateValue);
}
}
We might need to expose some APIs to provide a way to (de-)serialize State. With Json.NET, it doesn't actually need any changes to the library, here's a quick and dirty implementation of a JsonConverter: