通过自定义IContractResolver

时间:2017-09-15 04:56:48

标签: c# json.net

我有一个班级:

 public class MyClass
 {
    public MyEnum Foo{ get; set; }
 }

在序列化期间,我想改变

的输出
{
   "Foo": 1
}

{
   "Foo": "EnumName"
}

我已经尝试过创建一个IValueProvider,但是每走一步都会遇到死胡同。 (我的场景比声明的要复杂一点;我需要找到一种方法在IContractResolver中完全执行此操作。)

1 个答案:

答案 0 :(得分:2)

您可以创建一个继承自custom ContractResolverDefaultContractResolver,自动将StringEnumConverter应用于枚举或可枚举枚举的每个合约:

public class StringEnumContractResolver : DefaultContractResolver
{
    readonly StringEnumConverter converter;

    public StringEnumContractResolver() : this(true, false) { }

    public StringEnumContractResolver(bool allowIntegerValue, bool camelCaseText)
    {
        this.converter = new StringEnumConverter { AllowIntegerValues = allowIntegerValue, CamelCaseText = camelCaseText };
    }

    protected override JsonPrimitiveContract CreatePrimitiveContract(Type objectType)
    {
        var contract = base.CreatePrimitiveContract(objectType);
        var type = Nullable.GetUnderlyingType(contract.UnderlyingType) ?? contract.UnderlyingType;
        if (type.IsEnum && contract.Converter == null)
            contract.Converter = converter;
        return contract;
    }
}

注意:

  • 如果枚举类型已应用JsonConverter,则优先于默认StringEnumConverter

  • 将转换器添加到枚举本身的JsonPrimitiveContract,而不是返回枚举的成员的每个JsonProperty,确保将转换器应用于集合和词典中的枚举。

  • IValueProvider提供获取和设置值的方法,因此与转换器相比,此方法不太方便。您需要将枚举值的嵌套序列化和反序列化作为其中的JSON字符串执行,但它不是为此设计的,因此无法访问JSON读取器,编写器或序列化程序。此外,字典值或枚举的集合项没有值提供者。

  • 您可能希望缓存合约解析程序,以获得最佳效果,如here所述。

示例.Net fiddle