目前在.net-core-3.0中不支持开箱即用。当前存在一个未解决的问题Support for EnumMemberAttribute in JsonConverterEnum #31081请求此功能。在此期间,您将需要创建自己的JsonConverterFactory
序列化枚举,该枚举具有由属性指定的自定义值名称。
如果您需要使用自定义值名称往返枚举,则需要从头开始创建通用转换器 + 转换器工厂。这在一般情况下有些涉及,因为有必要处理整数和字符串值的解析,[Flags]
枚举值的每个组件的重命名,以及所有可能的基础类型(byte
、short
、int
、long
等ulong
)的枚举。
JsonStringEnumMemberConverter
当枚举用属性装饰时, fromMacross.Json.Extensions
似乎提供了此功能;[EnumMember(Value = "custom name")]
安装软件包Macross.Json.Extensions
,然后执行:
[JsonConverter(typeof(System.Text.Json.Serialization.JsonStringEnumMemberConverter))] // This custom converter was placed in a system namespace.
public enum Example
{
Trick,
Treat,
[EnumMember(Value = "Trick-Or-Treat")]
TrickOrTreat,
}
有关使用详细信息,请参阅此处的文档。
或者,您可以使用 Json.NETStringEnumConverter
作为参考模型来创建自己的模型。
如果您只需要使用自定义值名称序列化枚举,则可以通过创建一个来更轻松地完成此操作,该方法通过为每种类型构造一个自定义来JsonConverterFactory
适应,该类型查找枚举成员上是否存在属性,如果找到,则映射成员名称到属性的值。(我之所以选择这是因为这是 Newtonsoft 支持的属性。)JsonStringEnumConverter
JsonNamingPolicy
enum
[EnumMember(Value = "xxx")]
EnumMember
首先介绍如下转换器:
public class CustomJsonStringEnumConverter : JsonConverterFactory
{
private readonly JsonNamingPolicy namingPolicy;
private readonly bool allowIntegerValues;
private readonly JsonStringEnumConverter baseConverter;
public CustomJsonStringEnumConverter() : this(null, true) { }
public CustomJsonStringEnumConverter(JsonNamingPolicy namingPolicy = null, bool allowIntegerValues = true)
{
this.namingPolicy = namingPolicy;
this.allowIntegerValues = allowIntegerValues;
this.baseConverter = new JsonStringEnumConverter(namingPolicy, allowIntegerValues);
}
public override bool CanConvert(Type typeToConvert) => baseConverter.CanConvert(typeToConvert);
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
var query = from field in typeToConvert.GetFields(BindingFlags.Public | BindingFlags.Static)
let attr = field.GetCustomAttribute<EnumMemberAttribute>()
where attr != null
select (field.Name, attr.Value);
var dictionary = query.ToDictionary(p => p.Item1, p => p.Item2);
if (dictionary.Count > 0)
{
return new JsonStringEnumConverter(new DictionaryLookupNamingPolicy(dictionary, namingPolicy), allowIntegerValues).CreateConverter(typeToConvert, options);
}
else
{
return baseConverter.CreateConverter(typeToConvert, options);
}
}
}
public class JsonNamingPolicyDecorator : JsonNamingPolicy
{
readonly JsonNamingPolicy underlyingNamingPolicy;
public JsonNamingPolicyDecorator(JsonNamingPolicy underlyingNamingPolicy) => this.underlyingNamingPolicy = underlyingNamingPolicy;
public override string ConvertName (string name) => underlyingNamingPolicy == null ? name : underlyingNamingPolicy.ConvertName(name);
}
internal class DictionaryLookupNamingPolicy : JsonNamingPolicyDecorator
{
readonly Dictionary<string, string> dictionary;
public DictionaryLookupNamingPolicy(Dictionary<string, string> dictionary, JsonNamingPolicy underlyingNamingPolicy) : base(underlyingNamingPolicy) => this.dictionary = dictionary ?? throw new ArgumentNullException();
public override string ConvertName (string name) => dictionary.TryGetValue(name, out var value) ? value : base.ConvertName(name);
}
然后装饰你的enum
:
public enum Example
{
Trick,
Treat,
[EnumMember(Value = "Trick-Or-Treat")]
TrickOrTreat,
}
并按如下方式独立使用转换器:
var options = new JsonSerializerOptions
{
Converters = { new CustomJsonStringEnumConverter() },
WriteIndented = true,
};
var json = JsonSerializer.Serialize(values, options);
要将转换器注册到 asp.net 核心,请参阅例如这个对JsonConverter 等效的答案,即Mani Gandham的using System.Text.Json 。
笔记:
演示小提琴在这里。