如何使用json.net将枚举序列化为不同的属性名称

41

我有以下的枚举

public enum PermissionType
{
  [JsonProperty(PropertyName = "can_fly")]
  PermissionToFly,
  [JsonProperty(PropertyName = "can_swim")]
  PermissionToSwim
};

以及一个具有这个属性的类

[JsonProperty(PropertyName = "permissions", ItemConverterType = typeof(StringEnumConverter))]
public IList<PermissionType> PermissionKeynames { get; set; }`
我想将枚举列表序列化为字符串列表,序列化列表应使用PropertyName中指定的字符串(如“can_swim”),而不是属性的实际名称“PermissionToSwim”。但是,每当我调用JsonConvert.SerializeObject时,最终得到的结果是。
"permission_keynames":["PermissionToFly","PermissionToSwim"]

取代我所期望的

"permission_keynames":["can_fly","can_swim"]

我想在我的代码中使用短语“PermissionToSwim”,并将其序列化为另一个单词。 你有任何想法怎样可以实现这个? 我的直觉是注释引起的问题,但我还没有找到正确的注释。


1
如果将来有人遇到相反的问题(将数据反序列化为拥有不同命名值的枚举类型),可以查看这个问题的解答:https://dev59.com/Vmsz5IYBdhLWcg3wlY0n。 - pghprogrammer4
2个回答

73

看起来可以使用EnumMember属性(位于System.Runtime.Serialization中)使其工作。

public enum PermissionType
{
    [EnumMember(Value = "can_fly")]
    PermissionToFly,

    [EnumMember(Value = "can_swim")]
    PermissionToSwim
}
如果您使用这些属性,您也不需要在列表上的JsonProperty属性中设置ItemConverterType

太好了,谢谢!我之前看到过这个,但认为它不能与json.net一起使用,因为它是一个System.Runtime.Serialization注释。我不知道... - pghprogrammer4
7
这对我有用,不过关于你最后的评论,我仍然需要使用StringEnumConverter -- 否则,它会返回解析成整数的结果。 - Gyromite
4
我同意@Gyromite的观点。为了使它起作用,我必须这样做:1)序列化: var js = JsonConvert.SerializeObject(PermissionType.PermissionToFly,new StringEnumConverter());2)反序列化: var permissionType = JsonConvert.DeserializeObject <PermissionType>(js,new StringEnumConverter()); - Mykhailo Seniutovych
1
请注意,这不仅适用于Json.NET,还可能影响枚举的其他序列化方法,例如XML序列化。 - xr280xr

1
您可以通过使用 System.Reflection 中的 JsonProperty 属性定义自定义转换器来序列化枚举。
public class EnumByAttributesConverter<TEnum> : JsonConverter<TEnum>
    where TEnum : struct, Enum
{
    public override void WriteJson(JsonWriter writer, TEnum value, JsonSerializer serializer)
    {
        var valueName = value.ToString();
        var membersAttributes = GetMemberAttributePairs(value.GetType());
        var propertyName = membersAttributes.FirstOrDefault(item => item.Name == valueName)
            .Attribute?.PropertyName;
        writer.WriteValue(propertyName ?? valueName);
    }

    public override TEnum ReadJson(JsonReader reader, Type objectType, TEnum existingValue, 
        bool hasExistingValue, JsonSerializer serializer)
    {
        var name = reader.Value as string;
        var membersAttributes = GetMemberAttributePairs(objectType);
        var memberName = membersAttributes
            .FirstOrDefault(item => item.Attribute.PropertyName == name).Name;
        return Enum.TryParse<TEnum>(memberName ?? name, out var parsedResult)
            ? parsedResult
            : default;
    }

    private IReadOnlyCollection<(string Name, JsonPropertyAttribute Attribute)> GetMemberAttributePairs(Type type) =>
        type.GetMembers()
            .Select(member => (member.Name,
                Attribute: member.GetCustomAttributes(typeof(JsonPropertyAttribute), false)
                        .FirstOrDefault() as JsonPropertyAttribute))
            .Where(p => p.Attribute != null).ToArray();
}

您仍然需要定义JsonConverter属性,但这样可以避免在项目中混合使用System.Runtime.Serialization和Newtonsoft.Json。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接