Десериализацию последовательности в Json.NET можно сделать ленивой, но это не так автоматически. Вместо этого вам придется адаптировать один из ответов из Анализ большого файла json в .NET или Newtonsoft JSon Десериализовать в тип примитива к ф #.
Чтобы подтвердить, что десериализация последовательности не является ленивой по умолчанию, определите следующую функцию:
let jsonFromStream<'T>(stream : Stream) =
Console.WriteLine(typeof<'T>) // Print incoming type for debugging purpose
let serializer = JsonSerializer.CreateDefault()
use rdr = new StreamReader(stream, Encoding.UTF8, true, 4096, true)
use jrdr = new JsonTextReader(rdr, CloseInput = false)
let res = serializer.Deserialize<'T>(jrdr)
Console.WriteLine(res.GetType()) // Print outgoing type for debugging purpose
res
Тогда, если у нас есть поток stream
, содержащий массив объектов JSON someType
, и вызовите метод следующим образом:
let mySeq = jsonFromStream<someType seq>(stream)
Затем генерируется следующий отладочный вывод:
System.Collections.Generic.IEnumerable`1[Oti4jegh9906+someType]
System.Collections.Generic.List`1[Oti4jegh9906+someType]
Как видите, с точки зрения .Net, вызов JsonSerializer.Deserialize<T>()
с someType seq
- это то же самое, что вызов с IEnumerable<someType>
из c #, и в этом случае Json .NET материализует результат и возвращает его как List<someType>
.
Демонстрационная скрипка # 1 здесь .
Чтобы проанализировать массив JSON как ленивую последовательность, вам нужно будет вручную создать функцию seq
, которая выполняет итерации по JSON с JsonReader.Read()
и десериализует и возвращает каждую запись массива:
let jsonSeqFromStream<'T>(stream : Stream) =
seq {
// Adapted from this answer https://stackoverflow.com/a/35298655
// To https://stackoverflow.com/questions/35295220/newtonsoft-json-deserialize-into-primitive-type
let serializer = JsonSerializer.CreateDefault()
use rdr = new StreamReader(stream, Encoding.UTF8, true, 4096, true)
use jrdr = new JsonTextReader(rdr, CloseInput = false)
let inArray = ref false
while jrdr.Read() do
if (jrdr.TokenType = JsonToken.Comment) then
()
elif (jrdr.TokenType = JsonToken.StartArray && not !inArray) then
inArray := true
elif (jrdr.TokenType = JsonToken.EndArray && !inArray) then
inArray := false
else
let res = serializer.Deserialize<'T>(jrdr)
yield res
}
(Поскольку отслеживание, анализируем ли мы значения массива, является состоянием, это не выглядит очень функциональным. Может быть, это можно сделать лучше?)
Возвращение этой функции может быть использовано следующим образом, например ::
let mySeq = jsonSeqFromStream<someType>(stream)
mySeq |> Seq.iter (fun (s) -> printfn "%s" (JsonConvert.SerializeObject(s)))
Демонстрационная скрипка # 2 здесь .