I have a FileReader class whose job is to read and process text files using a StreamReader. To facilitate unit testing, I'd like to provide a type parameter to this class so that I can swap the StreamReader for a FakeReader that doesn't actually interact with the file system (and maybe throws exceptions such as OutOfMemory, so I can test the error handling in FileReader).
Ideally, I'd like to define FileReader something like this (trivialized for clarity):
type FileReader<'Reader> =
member this.Read file =
use sr = new 'Reader(file)
while not sr.EndOfStream do
printfn "%s" <| sr.ReadLine()
and simply define FakeReader to have a constructor that takes the file name, the EndOfStream property getter, the ReadLine() method, and the (empty) Dispose() method. However, F# has several complaints about this type definition, including "Calls to object constructors on type parameters cannot be given arguments." Since StreamReader has no default constructor, this approach seems like a no-go.
So far the only way I've gotten this to work is to inherit FakeReader from StreamReader:
type FakeReader() =
inherit StreamReader("") with
override this.ReadLine() = "go away"
member this.EndOfStream = false
member this.Dispose() = ()
and use a factory method that returns either a new FakeReader or a new StreamReader as appropriate.
type ReaderType = Fake | SR
let readerFactory (file : string, readerType) =
match readerType with
| Fake -> new FakeReader() :> StreamReader
| SR -> new StreamReader(file)
type FileReader(readertype) =
member this.Read file =
use sr = readerFactory(file, readertype)
while not sr.EndOfStream do
printfn "%s" <| sr.ReadLine()
This seems a lot less elegant. Is there a way to do this with a type parameter? Thanks to all.