С# Json.NET Render Flags Enum as String Array
В .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 }"
Ответы
Ответ 1
Вы должны реализовать свой собственный конвертер. Вот пример (особенно грязный и хакерский способ сделать это, но он служит хорошей демонстрацией):
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
Этот ответ немного отличается от сериализации, запрошенной OP, но, тем не менее, может быть полезен. Он основан на решении @davidg, но сериализованный JSON выглядит следующим образом (для 1 + 4 = 5):
{
"Val1": true,
"Val2": false,
"Val4": true,
"Val8": false
}
Оформление перечислений флагов такое же, как в ответе Давида:
[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;
}
}
Ответ 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
Я использовал ответ @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;
}