在Json.Net中将特定的枚举反序列化为system.enum [英] Deserialize specific enum into system.enum in Json.Net

查看:131
本文介绍了在Json.Net中将特定的枚举反序列化为system.enum的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  public class Rule 
{
///< summary>
///一般规则类型。
///< / summary>
public RuleType RuleType {get;组; }

///< summary>
///规则的人性化描述。
///< / summary>
public string RuleDescription {get;组; }

///< summary>
///规则的整数大小(如果适用)。
///< / summary>
public int? RuleInt {get;组; }

///< summary>
///与规则相关联的布尔符号(如果适用)。
///< / summary>
public bool? RuleBool {get;组; }

///< summary>
///与规则关联的枚举标志(如果适用)。可以为空。
///< / summary>
public System.Enum RuleFlagEnum {get;组; }

///< summary>
///对于任何其他随机垃圾的倾销,我在这个时间点未能解释。
///< / summary>
public object RuleObject {get;组; }
}

RuleType是一个特定的枚举,像这样:

  public枚举RuleType 
{
无效,
ModifyDifficulty,
StrengthChange,
ColorChange,
SignChange
}

使用Json.NET,这两个序列化和反序列化只是罚款。



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



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

  {
RuleType :SignChange,
RuleDescription:强度1反转门,
RuleInt:1,
RuleFlagEnum:负
}

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

  public enum SignChange 
{
零,
正,
否定
}

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



我真的很想把枚举保留在系统.Enum,所以我们可以加载任何任意的枚举,以供以后的解释规则类型,所以整个事情是可扩展的。这是可能的吗?

解决方案

这里的难点是 System.Enum 是一个抽象类,所以不可能将这种类型的未知混凝土类型的值反序列化。相反,需要在JSON中具有特定类型的信息,但是Json.NET会将枚举序列化为一个字符串或整数(取决于一个 StringEnumConverter 被应用) - 但不是一个对象,因此没有机会多态$ type属性被添加。



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

  public abstract class TypeWrapper 
{
protected TypeWrapper(){

[JsonIgnore]
public abstract object ObjectValue {get;

public static TypeWrapper CreateWrapper&T;(T value)
{
if(value == null)
返回新的TypeWrapper< T>();
var type = value.GetType();
if(type == typeof(T))
返回新的TypeWrapper< T>(value);
//返回子类的实际类型
return(TypeWrapper)Activator.CreateInstance(typeof(TypeWrapper<>))MakeGenericType(type),value);
}
}

公开封闭类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;组; }
}

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

  ///< summary> 
///与规则关联的枚举标志(如果适用)。可以为空。
///< / summary>
[JsonIgnore]
public System.Enum RuleFlagEnum {get;组; }

[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
},
}



I have a fairly generic 'rule' class that I am using to drive the behavior of an analysis engine I'm writing:

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 enum, like so:

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

Using Json.NET, that both serializes and deserializes just fine.

RuleEnum, however, is giving me problems. Whether using the default enum serialization or the string enum serialization, the specific type of enum is not provided. As such, during deserialization, I am left with System.Enum and a string value, which is wholly unhelpful.

This is an example of the serialization, to show what I'm talking about:

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

RuleFlagEnum, in this case, is referring to the enum:

public enum SignChange
{
    Zero,
    Positive,
    Negative
}

I have tried using all of the TypeNameHandling options inside Json.NET. They only put type hinting on the objects, which doesn't help with RuleFlagEnum since it is technically a primitive.

I would really, really like to keep the enum at System.Enum so we can load any arbitrary enum in for later interpretation by the rule type, so the entire thing is more expandable. Is this possible?

解决方案

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"
  },
}

这篇关于在Json.Net中将特定的枚举反序列化为system.enum的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆