Robert Sim
Robert Sim

Reputation: 1560

Properly disposing a stream in F#

The following code throws an ObjectDisposedException when reading from a file. It seems that the BinaryReader is going out of scope before the whole sequence is enumerated. What is the right way to make this call safely without leaking the reader? I prefer not to have to do stream management in the top-level code- ideally that is hidden away given a file path.

In this code, Edge.ReadBinary does the obvious task of deserializing an Edge from a binary stream. In my code the folder does something more complex but I've simplified it here just for readability.

let rec readEdges (br:BinaryReader) =
    seq {
        match Edge.ReadBinary br with
        | None -> yield! Seq.empty  
        | Some(e) -> yield e; yield! readEdges br        
    }

let readBinaryEdges fn =
    use br=new BinaryReader(File.OpenRead(fn))
    readEdges br

let sampled=readBinaryEdges fn |> Seq.fold (fun result l -> l::result) list.Empty 

Upvotes: 3

Views: 410

Answers (1)

Vandroiy
Vandroiy

Reputation: 6223

As pointed out in iljdarn's comment, putting use inside of a sequence expression fixes this. This works because the sequence expression builder defines its own semantics for the use keyword, to support disposal at the appropriate time. Thus, if you change the function to

let readBinaryEdges fn =
    seq { use br = new BinaryReader(File.OpenRead(fn))
          yield! readEdges br }

the reader will be disposed with the sequence.

Upvotes: 4

Related Questions