Comment désérialiser un objet JObject en .NET

241

J'utilise avec plaisir la bibliothèque Newtonsoft JSON . Par exemple, je créerais un à JObjectpartir d'un objet .NET, dans ce cas une instance d'Exception (pourrait ou non être une sous-classe)

if (result is Exception)
    var jobjectInstance = JObject.FromObject(result);

maintenant je sais que la bibliothèque peut désérialiser le texte JSON (c'est-à-dire une chaîne) en un objet

// only works for text (string)
Exception exception = JsonConvert.DeserializeObject<Exception>(jsontext); 

mais ce que je recherche c'est:

// now i do already have an JObject instance
Exception exception = jobjectInstance.????

Eh bien, il est clair que je peux retourner du JObjecttexte JSON et utiliser la fonctionnalité de désérialisation, mais cela me semble à l'envers.

Sébastien
la source

Réponses:

489

Selon cet article , c'est beaucoup mieux maintenant:

// pick out one album
JObject jalbum = albums[0] as JObject;

// Copy to a static Album instance
Album album = jalbum.ToObject<Album>();

Documentation: convertir JSON en un type

Tien Do
la source
10
Des idées sur les implications de performance ici? La réflexion sera-t-elle utilisée à chaque fois?
Shaun Rowan
1
Est-il possible de le faire avec un JsonConverter personnalisé?
Justin Skiles du
3
Merci pour l'astuce. Cela m'a beaucoup aidé. Permettez-moi d'ajouter quelque chose: dans une méthode générique où j'utilise type T, j'avais besoin de quelque chose comme result=(value is JObject) ? ((JObject)value).ToObject<T>() : (T)default(T);pour le convertir avec succès (note - valueest un objet provenant d'une base de données qui pourrait être un JObject ou autre chose dans ce cas, le résultat devrait être nul).
Matt
@ShaunRowan Jouant avec du code dans Linqpad, il semble que la réflexion soit utilisée pour faire correspondre la propriété au même "niveau" de l'objet cible que le champ correspondant dans l'objet JSON. Le nom de votre propriété doit correspondre au nom du champ JSON et le type de votre propriété doit être un type compatible.
BobbyA
et utilisez jobject.ToObject(myObject.GetType())si vous ne connaissez pas le type d'objet.
Tohid
45

De la documentation j'ai trouvé ceci

JObject o = new JObject(
   new JProperty("Name", "John Smith"),
   new JProperty("BirthDate", new DateTime(1983, 3, 20))
);

JsonSerializer serializer = new JsonSerializer();
Person p = (Person)serializer.Deserialize(new JTokenReader(o), typeof(Person));

Console.WriteLine(p.Name);

La définition de classe pour Persondoit être compatible avec les éléments suivants:

class Person {
    public string Name { get; internal set; }
    public DateTime BirthDate { get; internal set; }
}

Éditer

Si vous utilisez une version récente de JSON.net et n'avez pas besoin d'une sérialisation personnalisée, veuillez consulter la réponse de TienDo ci-dessus (ou ci-dessous si vous me votez: P), ce qui est plus concis.

Sébastien
la source
2
J'avais besoin d'utiliser cette approche, plutôt que le raccourci, pour pouvoir passer des paramètres de sérialisation personnalisés.
Justin Caldicott
Exact et je cherche
Mark-VII
2

Trop tard, juste au cas où quelqu'un chercherait un autre moyen:

void Main()
{
    string jsonString = @"{
  'Stores': [
    'Lambton Quay',
    'Willis Street'
  ],
  'Manufacturers': [
    {
      'Name': 'Acme Co',
      'Products': [
        {
          'Name': 'Anvil',
          'Price': 50
        }
      ]
    },
    {
      'Name': 'Contoso',
      'Products': [
        {
          'Name': 'Elbow Grease',
          'Price': 99.95
        },
        {
          'Name': 'Headlight Fluid',
          'Price': 4
        }
      ]
    }
  ]
}";

    Product product = new Product();
    //Serializing to Object
    Product obj = JObject.Parse(jsonString).SelectToken("$.Manufacturers[?(@.Name == 'Acme Co' && @.Name != 'Contoso')]").ToObject<Product>();

    Console.WriteLine(obj);
}


public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
Ivan Lopez
la source
Cela ressemble exactement à la réponse acceptée .
jpaugh