Newtonsoft(json.net)反序列化可以在F#中变为懒惰吗?

Newtonsoft(json.net)反序列化可以在F#中变为懒惰吗?,f#,json.net,lazy-evaluation,F#,Json.net,Lazy Evaluation,考虑下面的代码,它使用FSharp.Data从web资源请求数据 let resp = Http.RequestStream(url, headers, query) use rdr = new StreamReader(resp.ResponseStream) use jrdr = new JsonTextReader(rdr) let serializer = new JsonSerializer() let myArray = serializer.Deserialize<someT

考虑下面的代码,它使用FSharp.Data从web资源请求数据

let resp = Http.RequestStream(url, headers, query)
use rdr = new StreamReader(resp.ResponseStream)
use jrdr = new JsonTextReader(rdr)
let serializer = new JsonSerializer()
let myArray = serializer.Deserialize<someType[]>(jrdr).Value
如果我迭代mySeq并将其写入文本文件,是否所有内容都会从流中拖出并延迟反序列化?或者要求json.net进行反序列化的行为会迫使所有内容都在那个时候被急切地评估吗

更新

根据dbc的公认答案,函数式惰性函数如下所示

let jsonSeqFromStream<'T>(stream:Stream) = seq{
    let serializer = JsonSerializer.CreateDefault()
    use rdr = new StreamReader(stream, Encoding.UTF8, true, 4096, true)
    use jrdr = new JsonTextReader(rdr, CloseInput = false)
    let rec resSeq inArray = seq{
        if jrdr.Read() then
            match jrdr.TokenType with
            |JsonToken.Comment -> yield! resSeq inArray
            |JsonToken.StartArray when not inArray -> yield! resSeq true
            |JsonToken.EndArray when inArray -> yield! resSeq false
            |_ ->
                let resObj = serializer.Deserialize<'T>(jrdr)
                yield resObj
                yield! resSeq inArray
        else
            ()
    }
    yield! resSeq false
}
let jsonSeqFromStream(jrdr)
收益率
产量艾纳雷酒店
其他的
()
}
产量resSeq false
}

Json.NET可以使序列的反序列化变为惰性,但它不是自动进行的。相反,您必须将其中一个答案从f#改为f#

要确认序列的反序列化在默认情况下不是惰性的,请定义以下函数:

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
然后生成以下调试输出:

如您所见,从.Net的角度来看,使用
someType seq
调用与从c#使用
IEnumerable
调用它是一样的,在这种情况下,Json.Net会具体化结果并将其作为
列表返回

演示小提琴#1

要将JSON数组解析为惰性序列,您需要手动创建一个
seq
函数,该函数通过JSON进行迭代,并反序列化并生成每个数组条目:

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 jsonSeqFromStream(jrdr)
收益率
}
(因为跟踪是否解析数组值是有状态的,所以这看起来不是很实用。也许可以做得更好?)

此函数的返回可按如下方式使用,例如:

let mySeq = jsonSeqFromStream<someType>(stream)

mySeq |> Seq.iter (fun (s) -> printfn "%s" (JsonConvert.SerializeObject(s)))
让mySeq=jsonSeqFromStream(stream)
mySeq |>Seq.iter(乐趣)->printfn“%s”(JsonConvert.SerializeObject)))

演示小提琴2。

谢谢。我用你的解决方案的非变异版本更新了我的问题。看起来还好吗?没关系,它不起作用。它只返回序列中的第一个元素。不管怎样,我修好了。别介意我修好了程序错误。功能版本可以工作。
System.Collections.Generic.IEnumerable`1[Oti4jegh9906+someType]
System.Collections.Generic.List`1[Oti4jegh9906+someType]
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)))