通过装饰覆盖一个特定枚举的全局Json.NET枚举处理

通过装饰覆盖一个特定枚举的全局Json.NET枚举处理,json,asp.net-mvc,serialization,json.net,Json,Asp.net Mvc,Serialization,Json.net,我有一堆枚举,希望Json.NET将它们序列化为camelcased字符串。我的Global.asax.cs文件中有以下内容,并且工作正常: HttpConfiguration config = GlobalConfiguration.Configuration; config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter

我有一堆枚举,希望Json.NET将它们序列化为camelcased字符串。我的Global.asax.cs文件中有以下内容,并且工作正常:

HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter { CamelCaseText = true });
这使其成为如下所示的枚举:

public enum FavoriteWebSite {
    StackOverflow,
    GoogleNews
    // Etc
}
public enum Hobbies {
    Walking = 0x01,
    Biking = 0x02,
    // Etc
}
将序列化为“stackOverflow”、“googleNews”等值

但是,我有两个枚举是位掩码。为了使这成为一个简单的示例,假设其中一个如下所示:

public enum FavoriteWebSite {
    StackOverflow,
    GoogleNews
    // Etc
}
public enum Hobbies {
    Walking = 0x01,
    Biking = 0x02,
    // Etc
}
序列化此枚举实例时发生的情况取决于其中的值类型。例如:

Hobbies set1 = Hobbies.Walking;                  // Serializes as "walking" -- bad
Hobbies set2 = Hobbies.Walking | Hobbies.Biking; // Serializes as "3"       -- good!
我希望重写此枚举上的序列化,使其仅序列化为int,同时保留全局设置以使用camelcased字符串

我尝试删除全局配置,以便在默认情况下将枚举序列化为int,然后仅向非位掩码枚举添加
[JsonConverter(typeof(StringEnumConverter))]
。但是,这会导致这些对象的PascalCased序列化,而不是CamelCase序列化。在上面这样的方法装饰中使用StringEnumConverter时,我没有看到任何方法可以获得CamelCaseText属性集

总而言之,我们的目标是:

  • 将单值枚举序列化为pascalCased字符串
  • 将位掩码枚举序列化为int

  • 谢谢大家!

    您的主要困难似乎是您没有使用以下内容装饰您的标志枚举:

    [Flags]
    public enum Hobbies
    {
        Walking = 0x01,
        Biking = 0x02,
        // Etc
    }
    
    这是枚举的标志:

    设计标志枚举

    √ 不要将标志应用于枚举。不要将此属性应用于简单枚举

    另见。如果不这样做,许多与枚举相关的.Net实用程序可能无法像预期的那样用于标志枚举

    完成此操作后,将使用复合值将标志枚举序列化为一组逗号分隔的值,而不是当前看到的数值:

    如果您不希望这样做,并且仍然希望在JSON中看到标志枚举的默认数值,则可以将
    StringEnumConverter
    子类化,以仅转换非标志枚举:

    公共类非FlagStringEnumConverter:StringEnumConverter
    {
    公共覆盖布尔CanConvert(类型objectType)
    {
    如果(!base.CanConvert(objectType))
    返回false;
    return!HasFlagsAttribute(objectType);
    }
    静态布尔HasFlagsAttribute(类型objectType)
    { 
    返回属性.IsDefined(Nullable.GetUnderlyingType(objectType)??objectType,typeof(System.FlagsAttribute));
    }
    }
    
    然后像这样使用它:

    config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new NonFlagStringEnumConverter  { CamelCaseText = true });
    
    这将导致Json.NET退回到任何用于枚举的Json转换器上,或者退回到数值序列化(如果没有适用的退回)。演示小提琴#1

    此外,如果需要取代在更高级别应用的转换器并强制对标志枚举进行数字序列化,请使用以下命令:

    公共类ForceNumericFlagmConverter:JsonConverter
    {
    公共覆盖布尔CanConvert(类型objectType)
    {
    if(!(Nullable.GetUnderlyingType(objectType)??objectType.IsEnum)
    返回false;
    返回HasFlagsAttribute(objectType);
    }
    公共重写bool CanRead{get{return false;}}
    公共重写bool可以写入{get{return false;}}
    静态布尔HasFlagsAttribute(类型objectType)
    { 
    返回属性.IsDefined(Nullable.GetUnderlyingType(objectType)??objectType,typeof(System.FlagsAttribute));
    }
    公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
    {
    抛出新的NotImplementedException();
    }
    公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
    {
    抛出新的NotImplementedException();
    }
    }
    
    Demo fiddle#2.

    博客文章很好地解释了没有内置的方法来覆盖全局
    StringEnumConverter
    。您需要编写自己的转换器,它什么也不做,然后在转换JSON.NET时,它将返回该类型的默认转换器(对于枚举来说,它是序列化为它的数值)

    因此,如果您有全局转换器:

    config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(新的StringEnumConverter{CamelCaseText=true});
    
    您可以定义此
    ForceDefaultConverter
    converter

    公共类ForceDefaultConverter:JsonConverter
    {
    public override bool CanRead=>false;
    公共覆盖boolcanwrite=>false;
    public override bool CanConvert(Type objectType)=>抛出新的NotImplementedException();
    public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)=>抛出新的NotImplementedException();
    public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer)=>throw new NotImplementedException();
    }
    
    并在要覆盖默认值的属性上使用它

    公共类示例
    {
    [JsonConverter(类型(ForceDefaultConverter))]
    公共TestEnumValue{get;set;}
    }
    
    或者,如果在使用此枚举类型序列化所有对象时需要此数值,则在枚举类型本身上

    [JsonConverter(typeof(ForceDefaultConverter))]
    公共枚举测试数
    {
    Foo=1,
    巴=2
    }
    
    所以,您确实希望将一些枚举序列化为
    string
    ,而将一些枚举序列化为
    int
    ,对吗?此注释:
    //序列化为“walking”-bad
    使我认为您希望将它们全部序列化为
    int
    。顺便说一句,目标1是将单值枚举序列化为camelCased字符串,而不是PASCALCASE字符串。我说得对吗?@AFgone-我把你的小提琴叉在这里:,我看不出有什么问题。
    UserCan能力
    对象正在序列化为整数
    5
    ,这是此转换器所需的行为:
    [Flags]
    要序列化为int的枚举