EnumMemberAttribute 值被 DataContractJsonSerializer 忽略

EnumMemberAttribute Value is ignored by DataContractJsonSerializer

这是我的代码:

[DataContract] // (Name = "Type")]
 public enum Purpose
 {
   [EnumMember(Value = "definitionTarget")]
   DefinitionTarget = 0,
   [EnumMember(Value = "definitionSource")]
   DefinitionSource = 1,
   [EnumMember(Value = "semanticRole")]
   SemanticRole = 2,
   [EnumMember(Value = "dataType")]
   DataType = 3
}

我希望枚举值根据给定的字符串显示,而不是整数值。由于某种原因,这些值被忽略了。

序列化代码没什么特别的:

protected string GetRuntimeValue(RuntimeValue value)
{
    MemoryStream ms = new MemoryStream();
    _serializer.WriteObject(ms, value);
    return System.Text.Encoding.UTF8.GetString(ms.ToArray());
}

我去了 the Microsoft documentation 并找到了一个示例,其中包含一些样板代码,它们继承了 IExtensibleDataObject(没有解释原因)。我将代码添加到我的基础 class,没有变化。

我做错了什么?应该很简单,不是吗?

坏消息是 DataContractJsonSerializer 忽略了 EnumMember 属性,这是 by design:

Enumeration member values are treated as numbers in JSON, which is different from how they are treated in data contracts, where they are included as member names. ... The EnumMemberAttribute and the NonSerializedAttribute attributes are ignored if used.

Microsoft 支持代理也 confirmed this 并建议了一个 kludge,即公开一个用 DataMember 修饰的 属性 供序列化程序使用,它调用 Enum.GetName()获取枚举值的字符串名称。

在您的情况下需要将其修改为 return 首字母转换为小写的字符串:

[DataContract]
public class RuntimeValue
{
    public Purpose Purpose { get; set; }

    [DataMember(Name = "Purpose")]
    string PurposeString
    {
        get { return Enum.GetName(typeof(Purpose), this.Purpose).FirstCharacterToLower(); }
        set { this.Purpose = (Purpose)Enum.Parse(typeof(Purpose), value, true); }
    }
}

使用从 here 借来的扩展方法来做小写的东西:

public static string FirstCharacterToLower(this string str)
{
    if (String.IsNullOrEmpty(str) || Char.IsLower(str, 0))
        return str;

    return Char.ToLowerInvariant(str[0]) + str.Substring(1);
}

测试:

Console.WriteLine(GetRuntimeValue(new RuntimeValue()));

输出:

{"Purpose":"definitionTarget"}


我个人会尽可能使用 JSON.NET,但为了我的回答,我假设您已经考虑过该选项并且有充分的理由坚持使用此序列化程序。