将特定枚举反序列化为Json.Net中的system.enum

我有一个相当通用的“规则”类,我用它来驱动我正在编写的分析引擎的行为:

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

RuleType是一个特定的枚举,如下所示:

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

使用Json.NET,序列化和反序列化都很好。

然而,RuleEnum给了我一些问题。 无论使用默认枚举序列化还是字符串枚举序列化,都不提供特定类型的枚举。 因此,在反序列化期间,我留下了System.Enum和一个字符串值,这完全没有用。

这是序列化的一个例子,以显示我在说什么:

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

在这种情况下,RuleFlagEnum指的是枚举:

 public enum SignChange { Zero, Positive, Negative } 

我已经尝试使用Json.NET中的所有TypeNameHandling选项。 它们只对对象进行类型提示,这对RuleFlagEnum没有帮助,因为它在技术上是原始的。

我真的非常希望将枚举保存在System.Enum中,这样我们就可以加载任意枚举,以便以后通过规则类型进行解释,这样整个事情就更容易扩展了。 这可能吗?

这里的难点在于System.Enum是一个抽象类,因此不可能将未知具体类型的值反序列化为这样的类型。 相反,需要在JSON中的某个地方具有特定类型信息,但是Json.NET会将enum序列化为字符串或整数(取决于是否应用了StringEnumConverter ) – 而不是作为对象,因此不会有机会添加多态"$type"属性 。

在序列化时,解决方案是序列化可以传达具体类型信息的通用包装类:

 public abstract class TypeWrapper { protected TypeWrapper() { } [JsonIgnore] public abstract object ObjectValue { get; } public static TypeWrapper CreateWrapper(T value) { if (value == null) return new TypeWrapper(); var type = value.GetType(); if (type == typeof(T)) return new TypeWrapper(value); // Return actual type of subclass return (TypeWrapper)Activator.CreateInstance(typeof(TypeWrapper<>).MakeGenericType(type), value); } } public sealed class TypeWrapper : TypeWrapper { public TypeWrapper() : base() { } public TypeWrapper(T value) : base() { this.Value = value; } public override object ObjectValue { get { return Value; } } public T Value { get; set; } } 

然后在序列化类时使用序列化包装器:

  ///  /// The enum flag associated with the rule, if applicable. CAN be null. ///  [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; } } 

这会产生如下JSON:

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