gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 16:53:29 25 4
gpt4 key购买 nike

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

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

最佳答案

这里的困难在于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"
},
}

关于c# - 将特定枚举反序列化为 Json.Net 中的 system.enum,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31351262/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com