¿Puede Json.NET serializar / deserializar a / desde una secuencia?

He oído que Json.NET es más rápido que DataContractJsonSerializer, y quería probarlo …

Pero no pude encontrar ningún método en JsonConvert que tomara una secuencia en lugar de una cadena.

Para deserializar un archivo que contiene JSON en WinPhone, por ejemplo, uso el siguiente código para leer el contenido del archivo en una cadena y luego deserializarlo en JSON. Parece ser aproximadamente 4 veces más lento en mi prueba (muy ad-hoc) que usar DataContractJsonSerializer para deserializar directamente desde la transmisión …

// DCJS DataContractJsonSerializer dc = new DataContractJsonSerializer(typeof(Constants)); Constants constants = (Constants)dc.ReadObject(stream); // JSON.NET string json = new StreamReader(stream).ReadToEnd(); Constants constants = JsonConvert.DeserializeObject(json); 

¿Lo estoy haciendo mal?

Gracias,

Omri.

ACTUALIZACIÓN: Esto ya no funciona en la versión actual, ver a continuación la respuesta correcta ( no es necesario votar, esto es correcto en versiones anteriores ).

Utilice la clase JsonTextReader con un StreamReader o use la sobrecarga JsonSerializer que toma un StreamReader directamente:

 var serializer = new JsonSerializer(); serializer.Deserialize(streamReader); 

La versión actual de Json.net no le permite usar el código de respuesta aceptado. Una alternativa actual es:

 public static object DeserializeFromStream(Stream stream) { var serializer = new JsonSerializer(); using (var sr = new StreamReader(stream)) using (var jsonTextReader = new JsonTextReader(sr)) { return serializer.Deserialize(jsonTextReader); } } 

Documentación: Deserializar JSON de una secuencia de archivos

 public static void Serialize(object value, Stream s) { using (StreamWriter writer = new StreamWriter(s)) using (JsonTextWriter jsonWriter = new JsonTextWriter(writer)) { JsonSerializer ser = new JsonSerializer(); ser.Serialize(jsonWriter, value); jsonWriter.Flush(); } } public static T Deserialize(Stream s) { using (StreamReader reader = new StreamReader(s)) using (JsonTextReader jsonReader = new JsonTextReader(reader)) { JsonSerializer ser = new JsonSerializer(); return ser.Deserialize(jsonReader); } } 

Escribí una clase de extensión para ayudarme a deserializar de fonts JSON (cadena, secuencia, archivo).

 public static class JsonHelpers { public static T CreateFromJsonStream(this Stream stream) { JsonSerializer serializer = new JsonSerializer(); T data; using (StreamReader streamReader = new StreamReader(stream)) { data = (T)serializer.Deserialize(streamReader, typeof(T)); } return data; } public static T CreateFromJsonString(this String json) { T data; using (MemoryStream stream = new MemoryStream(System.Text.Encoding.Default.GetBytes(json))) { data = CreateFromJsonStream(stream); } return data; } public static T CreateFromJsonFile(this String fileName) { T data; using (FileStream fileStream = new FileStream(fileName, FileMode.Open)) { data = CreateFromJsonStream(fileStream); } return data; } } 

Deserializar ahora es tan fácil como escribir:

 MyType obj1 = aStream.CreateFromJsonStream(); MyType obj2 = "{\"key\":\"value\"}".CreateFromJsonString(); MyType obj3 = "data.json".CreateFromJsonFile(); 

Espero que ayude a alguien más.

Llegué a esta pregunta buscando una forma de transmitir una lista abierta de objetos a un System.IO.Stream y leerlos desde el otro extremo, sin almacenar toda la lista en la memoria antes de enviar. (Específicamente estoy transmitiendo objetos persistentes desde MongoDB sobre la API web).

@Paul Tyng y @Rivers hicieron un excelente trabajo respondiendo la pregunta original, y utilicé sus respuestas para construir una prueba de concepto para mi problema. Decidí publicar aquí la aplicación de la consola de prueba por si alguien más enfrenta el mismo problema.

 using System; using System.Diagnostics; using System.IO; using System.IO.Pipes; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json; namespace TestJsonStream { class Program { static void Main(string[] args) { using(var writeStream = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.None)) { string pipeHandle = writeStream.GetClientHandleAsString(); var writeTask = Task.Run(() => { using(var sw = new StreamWriter(writeStream)) using(var writer = new JsonTextWriter(sw)) { var ser = new JsonSerializer(); writer.WriteStartArray(); for(int i = 0; i < 25; i++) { ser.Serialize(writer, new DataItem { Item = i }); writer.Flush(); Thread.Sleep(500); } writer.WriteEnd(); writer.Flush(); } }); var readTask = Task.Run(() => { var sw = new Stopwatch(); sw.Start(); using(var readStream = new AnonymousPipeClientStream(pipeHandle)) using(var sr = new StreamReader(readStream)) using(var reader = new JsonTextReader(sr)) { var ser = new JsonSerializer(); if(!reader.Read() || reader.TokenType != JsonToken.StartArray) { throw new Exception("Expected start of array"); } while(reader.Read()) { if(reader.TokenType == JsonToken.EndArray) break; var item = ser.Deserialize(reader); Console.WriteLine("[{0}] Received item: {1}", sw.Elapsed, item); } } }); Task.WaitAll(writeTask, readTask); writeStream.DisposeLocalCopyOfClientHandle(); } } class DataItem { public int Item { get; set; } public override string ToString() { return string.Format("{{ Item = {0} }}", Item); } } } } 

Tenga en cuenta que puede recibir una excepción cuando se elimina el AnonymousPipeServerStream , ignoré esto ya que no es relevante para el problema en cuestión.