Deserialize specific enum into system.enum in Json.Net
Solution 1:
The difficulty here is that System.Enum
is an abstract class, so it is impossible to deserialize a value of unknown concrete type as such a type. Rather, one needs to have the specific type information in the JSON somewhere, however Json.NET will serialize an enum
as a string or an integer (depending upon whether a StringEnumConverter
is applied) -- but not an as an object, thus leaving no opportunity for a polymorphic "$type"
property to be added.
The solution is, when serializing, to serialize a generic wrapper class that can convey the concrete type information:
public abstract class TypeWrapper
{
protected TypeWrapper() { }
[JsonIgnore]
public abstract object ObjectValue { get; }
public static TypeWrapper CreateWrapper<T>(T value)
{
if (value == null)
return new TypeWrapper<T>();
var type = value.GetType();
if (type == typeof(T))
return new TypeWrapper<T>(value);
// Return actual type of subclass
return (TypeWrapper)Activator.CreateInstance(typeof(TypeWrapper<>).MakeGenericType(type), value);
}
}
public sealed class TypeWrapper<T> : TypeWrapper
{
public TypeWrapper() : base() { }
public TypeWrapper(T value)
: base()
{
this.Value = value;
}
public override object ObjectValue { get { return Value; } }
public T Value { get; set; }
}
Then use serialize the wrapper when serializing your class:
/// <summary>
/// The enum flag associated with the rule, if applicable. CAN be null.
/// </summary>
[JsonIgnore]
public System.Enum RuleFlagEnum { get; set; }
[JsonProperty("RuleFlagEnum", TypeNameHandling = TypeNameHandling.All)]
TypeWrapper RuleFlagEnumValue
{
get
{
return RuleFlagEnum == null ? null : TypeWrapper.CreateWrapper(RuleFlagEnum);
}
set
{
if (value == null || value.ObjectValue == null)
RuleFlagEnum = null;
else
RuleFlagEnum = (Enum)value.ObjectValue;
}
}
This produces JSON like the following:
{ "RuleType": "ModifyDifficulty", "RuleFlagEnum": { "$type": "Question31351262.TypeWrapper`1[[Question31351262.MyEnum, MyApp]], MyApp", "Value": "Two, Three" }, }