【问题标题】:Deserialize specific enum into system.enum in Json.Net将特定枚举反序列化为 Json.Net 中的 system.enum
【发布时间】:2015-07-10 22:26:34
【问题描述】:

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

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 是一个特定的枚举,如下所示:

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 中,这样我们就可以加载任意枚举,以便以后通过规则类型进行解释,这样整个事情就更具可扩展性。这可能吗?

【问题讨论】:

  • 您的意思是希望输出改为"RuleFlagEnum: "SignChange.Negative"
  • @cubrr:如果这意味着 Json.NET 可以正确反序列化它而无需编写完全自定义的反序列化处理程序,是的!
  • @OrelEraki:如果您阅读了这个问题,那绝对不是。我已经将枚举序列化为字符串。我的问题是将该字符串反序列化为正确的对象层次结构的一部分,但缺少关键数据以使其正常工作。
  • @YYY 你可能至少要编写一个自定义的 JsonConverter。
  • 对于将其标记为重复的其他人:我还想听听为什么这是一个我显然已经在实施“答案”的问题的重复。它甚至与序列化本身无关。它是关于反序列化的,如果序列化策略必须改变以允许适当的反序列化,那就这样吧。

标签: c# json serialization enums json.net


【解决方案1】:

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

解决办法是,在序列化的时候,序列化一个可以传达具体类型信息的泛型包装类:

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; }
}

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

    /// <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;
        }
    }

这会产生如下 JSON:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 2014-06-15
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 2017-06-16
    相关资源
    最近更新 更多