将json字符反序列化为枚举

时间:2013-08-31 18:25:29

标签: c# json json.net enumeration json-deserialization

我有一个用C#定义的枚举,我将它的值存储为字符,如下所示:

public enum CardType
{
    Artist = 'A',
    Contemporary = 'C',
    Historical = 'H',
    Musician = 'M',
    Sports = 'S',
    Writer = 'W'
}

我正在尝试使用JSON.NET反序列化,但传入的JSON是使用CHAR值(字符串)而不是枚举的int值编写的,如下所示:

[{"CardType","A"},{"CardType", "C"}]

是否可以定义某种转换器,允许我手动将char解析为枚举值?

我尝试创建一个JsonConverter,但我不知道该怎么做,只是将它应用于此属性而不是整个解析对象。这是我试过的:

public class EnumerationConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }

        int value = serializer.Deserialize<int>(reader);
        return (CardType)value;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsSubclassOf(typeof(string));
    }
}

逻辑可能是错的,我可以解决这个问题,但问题是ReadJson()根本没有被调用。

CanConvert是,但它似乎是为每个属性调用,而不仅仅是我为其定义的一个属性:

public class Card
{
            private CardType type;
        [JsonConverter(typeof(EnumerationConverter))]
        public CardType Type
        {
            get { return type; }
            set { type = value; }
        }
}

我确定我做错了,但我找不到如何为单个字段执行此操作的文档......

我错过了什么?

4 个答案:

答案 0 :(得分:28)

您无需自定义JsonConverter即可使用内置StringEnumConverterEnumMemberAttribute(来自System.Runtime.Serialization程序集)的组合。

如果没有EnumMemberAttribute,它会使用枚举名称,如艺术家,当代等,所以你需要将它的名称改为你的A,C等值。

但它不是最好的解决方案,因为你必须重复两次你的值,但它有效:

[JsonConverter(typeof(StringEnumConverter))]
public enum CardType
{
    [EnumMember(Value = "A")]
    Artist = 'A',
    [EnumMember(Value = "C")]
    Contemporary = 'C',
    [EnumMember(Value = "H")]
    Historical = 'H',
    [EnumMember(Value = "M")]
    Musician = 'M',
    [EnumMember(Value = "S")]
    Sports = 'S',
    [EnumMember(Value = "W")]
    Writer = 'W'
}

答案 1 :(得分:6)

此代码完美无缺:

CardType[] array = { CardType.Artist, CardType.Contemporary };
string s = JsonConvert.SerializeObject(array);
var array2 = JsonConvert.DeserializeObject<CardType[]>(s);

<强>更新
开箱即用StringEnumConverter

[JsonConverter(typeof(StringEnumConverter))]
public CardType Type { get; set; }

答案 2 :(得分:1)

你可以添加SerializerSettings.Converters.Add(new StringEnumConverter());

到您的BrowserJsonFormatter类

public class BrowserJsonFormatter : JsonMediaTypeFormatter
{
    public BrowserJsonFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
        SerializerSettings.Formatting = Formatting.Indented;
        SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
        SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        SerializerSettings.Converters.Add(new EmptyToNullConverter());
        SerializerSettings.Converters.Add(new StringEnumConverter());
        //SerializerSettings.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate;
    }

    public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
    {
        base.SetDefaultContentHeaders(type, headers, mediaType);
        headers.ContentType = new MediaTypeHeaderValue("application/json");
    }
}

答案 3 :(得分:0)

这是使用自定义 JsonConverter 对我有用的方法。我白天是一名 Java 开发人员,所以也许专家 C# 开发人员可以改进这一点或发现任何问题。

public class CharEnumConverter<T> : JsonConverter<T>
{
    public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer)
    {
        char c = (char)(int)Enum.Parse(typeof(T), value.ToString());
        writer.WriteValue(c + "");
    }

    public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        string stringValue = (string)reader.Value;
        char charValue = stringValue[0];
        int intValue = (int)charValue;
        string intValueString = intValue + "";

        if (Enum.IsDefined(typeof(T), intValue)) {
            T result = (T)Enum.Parse(typeof(T), intValueString);
            return result;
        } else {
            throw new Exception("Char value [" + charValue + "] is not defined for Enum [" + typeof(T).Name + "]");
        }
    }
}

我想作为 Json 读/写的枚举的示例用法。

[CharEnum]    
public enum MyEnum {
    NONE = 'A',
    YAY = 'B'
}

public class MyClass {

    [JsonConverter(typeof(CharEnumConverter<MyEnum>))]    
    public MyEnum myfield;

}

它将从 JSON 字符串中读取一个 'A' 到一个值为 NONE 的枚举字段中。 它会将值为 YAY 的枚举字段写入 JSON 字符串作为 'B'