【问题标题】:C# Json.NET Render Flags Enum as String ArrayC# Json.NET 将枚举标记为字符串数组
【发布时间】:2017-08-25 20:56:40
【问题描述】:

在 .NET 应用程序中,我有一组值存储为 [Flags] enum。我想将这些序列化为 json,但我不想让结果为整数,而是为活动的标志获取一个字符串数组。

所以如果我有以下代码

[Flags]
public enum F
{
    Val1 = 1,
    Val2 = 2,
    Val4 = 4,
    Val8 = 8

}

public class C
{        
    public F Flags { get; set; }
}

string Serialize() {
    return JsonConvert.SerializeObject(new C { Flags = F.Val1 | F.Val4 });
}

我希望Serialize() 方法返回:

"{ Flags: [ "Val1", "Val4" ] }"

代替:

"{ Flags: 5 }"

【问题讨论】:

  • 你的意思是JsonConvert.SerializeObject(new C { Flags = F.Val1 | F.Val4 });
  • {"Flags":"Val1, Val4"} 可以接受吗?
  • @MattJones 是的。固定
  • @DavidG 我们不希望。
  • 您可能需要为您的特定枚举实现自定义 JsonConverter 类。

标签: c# json enums json.net


【解决方案1】:

您必须实现自己的转换器。这是一个例子(一种特别肮脏和hacky的做法,但它是一个很好的演示):

public class FlagConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader,  Type objectType, Object existingValue, JsonSerializer serializer)
    {
        //If you need to deserialize, fill in the code here
        return null;
    }

    public override void WriteJson(JsonWriter writer, Object value, JsonSerializer serializer)
    {
        var flags = value.ToString()
            .Split(new[] { ", " }, StringSplitOptions.RemoveEmptyEntries)
            .Select(f => $"\"{f}\"");

        writer.WriteRawValue($"[{string.Join(", ", flags)}]");
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

现在像这样装饰你的枚举:

[Flags]
[JsonConverter(typeof(FlagConverter))]
public enum F
{
    Val1 = 1,
    Val2 = 2,
    Val4 = 4,
    Val8 = 8
}

您的示例序列化代码现在将输出以下内容:

{"Flags":["Val1", "Val4"]}

【讨论】:

    【解决方案2】:

    装饰你的enum

    [Flags]
    [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
    public enum F
    {
        Val1 = 1,
        Val2 = 2,
        Val4 = 4,
        Val8 = 8
    }
    

    输出:

    {"标志":"Val1, Val4"}

    我意识到 JSON 不是您问题中的数组,不确定这是否是必需的,因为这也是有效的 JSON。

    【讨论】:

    • 我可以从上面的评论中看到你更喜欢数组,我不确定那个是不是我的头顶。
    【解决方案3】:

    我在上面使用了@DavidG 的答案,但需要 ReadJson 的实现。以下是我整理的:

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        int outVal = 0;
        if (reader.TokenType == JsonToken.StartArray)
        {
            reader.Read();
            while (reader.TokenType != JsonToken.EndArray)
            {
                outVal += (int)Enum.Parse(objectType, reader.Value.ToString());
                reader.Read();
            }
        }
        return outVal;
    }
    

    【讨论】:

      【解决方案4】:
       public static string ConvertEnumsToJson<T>(Type e)
              {
      
                  var ret = "{";
                  var index = 0;
                  foreach (var val in Enum.GetValues(e))
                  {
                      if (index > 0)
                      {
                          ret += ",";
                      }
                      var name = Enum.GetName(e, val);
                      ret += name + ":" + ((T)val) ;
                      index++;
                  }
                  ret += "}";
                  return ret;
      
              }
      

      使用喜欢

      ConvertEnumsToJson<byte>(typeof(AnyEnum))
      

      【讨论】:

        【解决方案5】:

        这个答案与 OP 要求的序列化略有不同,但可能仍然有用。它基于@davidg 的解决方案,但序列化的 JSON 看起来像这样(对于 1+4=5):

        {
            "Val1": true,
            "Val2": false,
            "Val4": true,
            "Val8": false  
        }
        

        flags 枚举的装饰与 Davids 回答中的相同:

        [Flags]
        [JsonConverter(typeof(FlagConverter))]
        public enum F
        {
            Val1 = 1,
            Val2 = 2,
            Val4 = 4,
            Val8 = 8
        }
        

        但这里有一个不同的WriteJson 方法和ReadJson 方法的最小工作示例。

        public class FlagConverter : JsonConverter
        {
            public override object ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
            {
                JToken token = JToken.Load(reader);
                JObject jobject = JObject.FromObject(token);
                F result = 0;
                foreach (F f in Enum.GetValues(typeof(F)))
                {
                    if (jobject[f.ToString()] != null && (bool)jobject[f.ToString()])
                    {
                        result |= f; // key is present and value is true ==> set flag
                    }
                }
                return result;
            }
        
            public override void WriteJson(JsonWriter writer, Object value, JsonSerializer serializer)
            {
                JObject result = new JObject();
                F f = (F)value;
                foreach (F f in Enum.GetValues(typeof(F)))
                {
                    result[f.ToString()] = status.HasFlag(f);
                }
                writer.WriteRawValue(JsonConvert.SerializeObject(result));
            }
        
            public override bool CanConvert(Type objectType)
            {
                return true;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2017-06-16
          • 1970-01-01
          • 1970-01-01
          • 2013-09-09
          • 2015-06-10
          • 2011-06-14
          • 1970-01-01
          • 2014-09-27
          • 1970-01-01
          相关资源
          最近更新 更多