web-dev-qa-db-fra.com

Comment demander à JSON.NET de désérialiser JArray en un objet List <object> lorsque le type d'objet est fourni?

Ayons la classe suivante:

class Foo
{
    public object Any;
}

Cette classe accepte n'importe quoi dans le champ Any.

Quand j'appelle:

JsonConvert.DeserializeObject<Foo>("{any: 5}")

Any contient System.Int64.

Cependant, quand j'appelle:

JsonConvert.DeserializeObject<Foo>("{any: [5]}")

Any contient Newtonsoft.Json.Linq.JArray.

Comment configurer JSON.NET pour que, dans ce cas, Any contienne List<object>?

CLARIFICATION:

Il peut y avoir n'importe quoi, je peux appeler:

JsonConvert.DeserializeObject<Foo>("{any: 'c'}")

ou

JsonConvert.DeserializeObject<Foo>("{any: ['c', 5]}")

Plus de précision:

Je voudrais dire en quelque sorte à JSON.NET (peut-être en utilisant JsonSerializerSettings):

Lorsque vous rencontrez object et que JSON contient un tableau, désérialisez-le en (par exemple) List<object>.

7
TN.

Actuellement, je me suis moqué de la solution suivante:

public class MyObjectConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object);
    }

    public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        switch (reader.TokenType)
        {
            case Newtonsoft.Json.JsonToken.StartArray:
                return JToken.Load(reader).ToObject<List<object>>(); 
            case Newtonsoft.Json.JsonToken.StartObject:
                return JToken.Load(reader).ToObject<Dictionary<string, object>>(); 
            default:
                if (reader.ValueType == null && reader.TokenType != Newtonsoft.Json.JsonToken.Null)
                    throw new NotImplementedException("MyObjectConverter");
                return reader.Value;
        }
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException("MyObjectConverter");
    }
}

Le problème de cette solution est qu’elle doit également gérer les autres types. Cela pourrait échouer lorsque reader.TokenType n'est ni StartArray ni StartObject et que reader.ValueType est null. Espérons que quelqu'un fournira une meilleure solution.

2
TN.

Votre réponse est probablement ici

Votre [5] est un tableau. Tout ce que vous avez à faire est de le lancer dans une liste. 


Vous pouvez également créer votre propre convertisseur, comme décrit ici

2
Daniel Möller

Je pense que vous pourriez faire cela avec un JsonConverter. Le convertisseur ci-dessous convertit JArrays en listes d'objets lorsque le champ any est un JArray et revient au comportement par défaut de any dans tous les autres cas. Sur la base de votre description, c’est exactement ce que vous recherchez. Je soupçonne que le code pourrait être amélioré, mais cela devrait vous donner le chemin vers une solution:

public class ListJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        var theFoo = new Foo();

        dynamic dynamicObject = serializer.Deserialize(reader);

        if (dynamicObject.any.GetType() == typeof (JArray))
        {
            var items = new List<object>();

            foreach (var item in dynamicObject.any)
            {
                items.Add(item);
            }

            theFoo.Any = items;
        }
        else
        {
            theFoo.Any = dynamicObject.any.Value;
        }

        return theFoo;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof (Foo);
    }

    public override bool CanRead
    {
        get { return true; }
    }

    public override bool CanWrite
    {
        get { return false; }
    }
}

Usage:

var bar = JsonConvert.DeserializeObject<Foo>("{any: ['c', 5]}", new ListJsonConverter());
0
Rob Davis