Cómo deserializar un objeto JObject to .NET

241

Felizmente uso la biblioteca Newtonsoft JSON . Por ejemplo, crearía un a JObjectpartir de un objeto .NET, en este caso una instancia de Exception (podría o no ser una subclase)

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

ahora sé que la biblioteca puede deserializar el texto JSON (es decir, una cadena) a un objeto

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

pero lo que busco es:

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

Bueno, está claro que puedo JObjectvolver al texto JSON y luego usar la funcionalidad de deserialización, pero eso me parece al revés.

Sebastian
fuente

Respuestas:

489

Según esta publicación , ahora es mucho mejor:

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

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

Documentación: Convertir JSON a un tipo

Tien Do
fuente
10
¿Alguna idea sobre las implicaciones de rendimiento aquí? ¿Se utilizará la reflexión cada vez?
Shaun Rowan
1
¿Es posible hacer esto con un JsonConverter personalizado?
Justin Skiles
3
gracias por la pista. Me ayudó mucho. Permítanme agregar algo: en un método genérico en el que estoy usando el tipo T, requería algo como result=(value is JObject) ? ((JObject)value).ToObject<T>() : (T)default(T);convertirlo con éxito (nota: valuees un objeto que proviene de una base de datos que podría ser un JObject u otra cosa en cuyo caso el resultado debería ser nulo).
Matt
@ShaunRowan Al jugar con el código en Linqpad, parece que la reflexión se usa para hacer coincidir la propiedad en el mismo "nivel" del objeto de destino que el campo correspondiente en el objeto JSON. El nombre de su propiedad debe coincidir con el nombre del campo JSON, y el tipo de su propiedad debe ser un tipo compatible.
BobbyA
y úsalo jobject.ToObject(myObject.GetType())si no conoces el tipo de objeto.
Tohid
45

De la documentación encontré esto

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 definición de clase para Persondebería ser compatible con lo siguiente:

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

Editar

Si está utilizando una versión reciente de JSON.net y no necesita una serialización personalizada, consulte la respuesta de TienDo arriba (o abajo si me votó: P), que es más conciso.

Sebastian
fuente
2
Necesitaba usar este enfoque, en lugar de la taquigrafía, para poder pasar configuraciones de serialización personalizadas.
Justin Caldicott
Exacto y estoy buscando
Mark-VII
2

Demasiado tarde, por si alguien está buscando otra manera:

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
fuente
Esto se ve exactamente como la respuesta aceptada .
jpaugh