简体   繁体   中英

How to serialize list of enum using their string value

This is my enum type:

public enum AccessScope
{
    [JsonProperty("read_content")]
    ReadContent,

    [JsonProperty("write_content")]
    WriteContent,

    [JsonProperty("read_themes")]
    ReadThemes,

    [JsonProperty("write_themes")]
    WriteThemes
}  

I want to serialize this enum using the string values... when I try the following code, the numeric values are used for serialization:

[TestMethod]
public void Serialize_access_scopes()
{
    var requiredPermissions = new List<AccessScope>()
    {
        AccessScope.ReadContent,
        AccessScope.WriteContent,
    };

    var commaSeparatedPermissions = JsonConvert.SerializeObject(requiredPermissions);  

    commaSeparatedPermissions.Should().Be("read_content, write_content");
}

艾尔齐

You could use the StringEnumConverter provided by Json.Net rather than defining a custom converter, along with using the EnumMemberAttribute instead of JsonPropertyAttribute .

For Example,

[JsonConverter(typeof(StringEnumConverter))]
public enum AccessScope
{
    [EnumMember(Value="read_content")]
    ReadContent,

    [EnumMember(Value="write_content")]
    WriteContent,

    [EnumMember(Value="read_themes")]
    ReadThemes,

    [EnumMember(Value="write_themes")]
    WriteThemes
} 

Now you can deserialize as

var requiredPermissions = new List<AccessScope>()
{
    AccessScope.ReadContent,
    AccessScope.WriteContent,
};

var result = JsonConvert.SerializeObject(requiredPermissions);

Output

["read_content","write_content"]

You need a custom converter; perhaps:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;

static class P
{
    class ByNameStringEnumConverter : StringEnumConverter
    {
        static ConcurrentDictionary<Type, (string name, object value)[]> s_byTypeCache = new ConcurrentDictionary<Type, (string name, object value)[]>();

        static (string name, object value)[] GetMap(Type type) => s_byTypeCache.TryGetValue(type, out var result) ? result : AddForType(type);
        static (string name, object value)[] AddForType(Type type)
        {
            var fields = type.GetFields(BindingFlags.Static | BindingFlags.Public);
            var map = Array.ConvertAll(fields, field =>
            {
                string name = field.Name;
                if (Attribute.GetCustomAttribute(field, typeof(JsonPropertyAttribute)) is JsonPropertyAttribute jprop
                    && !string.IsNullOrWhiteSpace(jprop.PropertyName))
                {
                    name = jprop.PropertyName;
                }
                return (name, field.GetValue(null));
            });
            s_byTypeCache.TryAdd(type, map);
            return map;
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.String && reader.Value is string s && objectType.IsEnum)
            {
                var map = GetMap(objectType);
                for (int i = 0; i < map.Length; i++)
                    if (map[i].name == s) return map[i].value;
            }
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            Type type = value?.GetType();
            if (type is object && type.IsEnum)
            {
                var map = GetMap(type);
                for (int i = 0; i < map.Length; i++)
                {
                    if (Equals(map[i].value, value))
                    {
                        writer.WriteValue(map[i].name);
                        return;
                    }
                }
            }
            base.WriteJson(writer, value, serializer);
        }
    }
    [JsonConverter(typeof(ByNameStringEnumConverter))]
    public enum AccessScope
    {
        [JsonProperty("read_content")]
        ReadContent,

        [JsonProperty("write_content")]
        WriteContent,

        [JsonProperty("read_themes")]
        ReadThemes,

        [JsonProperty("write_themes")]
        WriteThemes
    }
    static void Main()
    {
        var requiredPermissions = new List<AccessScope>()
        {
            AccessScope.ReadContent,
            AccessScope.WriteContent,
        };

        var json = JsonConvert.SerializeObject(requiredPermissions);

        Console.WriteLine(json);

        // and back again
        var obj = JsonConvert.DeserializeObject<List<AccessScope>>(json);
        foreach(var val in obj)
            Console.WriteLine(val);
    }
}

Add following namespace in your class

System.Text.Json.Serialization

and also add following annotation above your enum. It will working fine in .NET6

[JsonConverter(typeof(JsonStringEnumConverter))]

using System.Runtime.Serialization;
using System.Text.Json.Serialization;

namespace AppService.Enums
{
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public enum AccessScope
    {
        [EnumMember(Value = "read_content")]
        ReadContent,

        [EnumMember(Value = "write_content")]
        WriteContent,

        [EnumMember(Value = "read_themes")]
        ReadThemes,

        [EnumMember(Value = "write_themes")]
        WriteThemes
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM