将特定枚举反序列化到系统中.枚举
本文关键字:枚举 系统 反序列化 | 更新日期: 2023-09-27 18:02:14
我有一个相当通用的"规则"类,我正在使用它来驱动我正在编写的分析引擎的行为:
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是一个特定的enum,如下所示:
public enum RuleType
{
Invalid,
ModifyDifficulty,
StrengthChange,
ColorChange,
SignChange
}
使用Json。. NET,序列化和反序列化都很好。
然而,RuleEnum给我带来了问题。无论是使用默认enum序列化还是使用字符串enum序列化,都不提供enum的特定类型。因此,在反序列化过程中,我只剩下System.Enum
和一个字符串值,这是完全没有帮助的。
这是一个序列化的例子,来展示我在说什么:
{
"RuleType": "SignChange",
"RuleDescription": "Strength 1 Inversion Gate",
"RuleInt": 1,
"RuleFlagEnum": "Negative"
}
RuleFlagEnum,在这种情况下,指的是enum:
public enum SignChange
{
Zero,
Positive,
Negative
}
我已经尝试使用Json.NET内的所有TypeNameHandling
选项。他们只在对象上添加类型提示,这对RuleFlagEnum没有帮助,因为它在技术上是一个原语。
我真的,真的想把enum保留在System。枚举,这样我们就可以加载任意的枚举,以便稍后通过规则类型进行解释,所以整个东西更具可扩展性。这可能吗?
这里的难点在于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>(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" }, }