web-dev-qa-db-fra.com

Désérialiser le caractère json en tant qu'énumération

J'ai une énumération définie avec C #, où je stocke ses valeurs sous forme de caractères, comme ceci:

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

J'essaie de désérialiser en utilisant JSON.NET, mais le JSON entrant a été écrit en utilisant la valeur CHAR (chaîne) au lieu de la valeur int de l'énumération, comme ceci:

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

Est-il possible de définir une sorte de convertisseur qui me permettra d'analyser manuellement le caractère à la valeur enum?

J'ai essayé de créer un JsonConverter, mais je ne sais pas comment le faire, tout en l'appliquant uniquement à cette propriété et non à l'ensemble de l'objet analysé. voici ce que j'ai essayé:

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));
    }
}

La logique peut être erronée et je peux résoudre ce problème, mais le problème est que ReadJson () n'est pas du tout appelé.

CanConvert l'est, mais il semble être appelé pour chaque propriété, pas seulement pour la propriété pour laquelle je l'ai défini:

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

Je suis sûr que j'ai mal fait cela, mais j'ai du mal à trouver de la documentation sur la façon de le faire pour un seul champ ...

Qu'est-ce que je rate?

25
SelAromDotNet

Vous n'avez pas nécessairement besoin d'un JsonConverter personnalisé, vous pouvez utiliser le StringEnumConverter intégré avec la combinaison de EnumMemberAttribute (à partir du System.Runtime.Serialization Assemblée).

Sans le EnumMemberAttribute, il utilise les noms d'énumération Artist, Contemporary, etc., vous devez donc modifier les noms avec celui-ci en votre valeur A, C, etc.

Mais ce n'est pas la meilleure solution car vous devez répéter vos valeurs deux fois, mais cela fonctionne:

[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'
}
37
nemesv

Ce code fonctionne parfaitement:

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

Mise à jour:
Qu'en est-il de la boîte d'origine StringEnumConverter:

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

Vous pouvez simplement ajouter SerializerSettings.Converters.Add (new StringEnumConverter ());

à votre classe 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");
    }
}
1
David-Paul Brown