Deserialize a specific enumeration in system.enum in Json.Net

I have a fairly general class of rules that I use to control the behavior of the analysis engine that I write:

public class Rule { /// <summary> /// The general rule type. /// </summary> public RuleType RuleType { get; set; } /// <summary> /// The human-readable description of the rule. /// </summary> public string RuleDescription { get; set; } /// <summary> /// The integer magnitude of the rule, if applicable. /// </summary> public int? RuleInt { get; set; } /// <summary> /// The boolean sign associated with the rule, if applicable. /// </summary> public bool? RuleBool { get; set; } /// <summary> /// The enum flag associated with the rule, if applicable. CAN be null. /// </summary> public System.Enum RuleFlagEnum { get; set; } /// <summary> /// A dumping ground for any other random crap I've failed to account for at this point in time. /// </summary> public object RuleObject { get; set; } } 

RuleType is a specific enumeration, for example:

 public enum RuleType { Invalid, ModifyDifficulty, StrengthChange, ColorChange, SignChange } 

Using Json.NET, which is both serialized and deserialized, is just fine.

RuleEnum, however, gives me problems. Regardless of whether you use default serialization of enum or serialization of line enumeration, a specific type of enumeration is not provided. So, during deserialization, I stay with System.Enum and a string value that is completely useless.

This is a serialization example to show what I'm talking about:

 { "RuleType": "SignChange", "RuleDescription": "Strength 1 Inversion Gate", "RuleInt": 1, "RuleFlagEnum": "Negative" } 

RuleFlagEnum in this case refers to the enumeration:

 public enum SignChange { Zero, Positive, Negative } 

I tried to use all TypeNameHandling parameters inside Json.NET. They only put a hint type on objects, which does not help with RuleFlagEnum, since it is technically primitive.

I would very much like to save enum in System.Enum so that we can load any arbitrary enumeration for later interpretation by the type of rule, so all this becomes more extensible. Is it possible?

+3
source share
1 answer

The difficulty here is that System.Enum is an abstract class, so it is not possible to deserialize the value of an unknown concrete type as such a type. Rather, in JSON you need to have certain type information, however Json.NET will serialize enum as a string or an integer (depending on whether there will be a StringEnumConverter ), but not as an object, leaving no room for the polymorphic property "$type" for additions.

A serialization solution serializes a common wrapper class that can convey information of a specific type:

 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 shell serialization 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 creates JSON as shown below:

 { "RuleType": "ModifyDifficulty", "RuleFlagEnum": { "$type": "Question31351262.TypeWrapper`1[[Question31351262.MyEnum, MyApp]], MyApp", "Value": "Two, Three" }, } 
+2
source

Source: https://habr.com/ru/post/1243722/


All Articles