Search code examples
oopf#filehelpers

FileHelpers BadUsageException only on compiled F# but not in script


I wrote an fsi script that worked great and wanted to compile it so that I could move it easier. However, when I compiled it, all of a sudden FileHelpers began giving errors.

The following code uses FileHelpers 2.9.9. It is a minimal working example to illustrate the issue, test.fsx:

#r "FileHelpers.dll"

open FileHelpers

[<DelimitedRecord(",")>]
type Type = 
    val field1 : string
    val field2 : int
    override x.ToString() = sprintf "%s: %d" x.field1 x.field2

let readFile<'a> file = seq {
    use engine1 = new FileHelperAsyncEngine(typeof<'a>)
    use tmp1 = engine1.BeginReadFile(file)

    engine1.ReadNext() |> ignore

    while engine1.LastRecord <> null do
        yield engine1.LastRecord :?> 'a
        engine1.ReadNext() |> ignore
    }


readFile<Type> "test.csv" |> Seq.iter (printfn "%A")

with the file test.csv as

test1,1
test2,2
test3,3

If I run the code as fsi .\test.fsx it will work fine. However, if I try to compile it with fsc .\test.fsx and run .\test.exe I get the error Unhandled Exception: FileHelpers.BadUsageException: The record class Type needs a constructor with no args (public or private). A work around that works in both scripting and compiled mode is

[<DelimitedRecord(",")>]
type Type () = 
    [<DefaultValue>]
    val mutable field1 : string
    [<DefaultValue>]
    val mutable field2 : int
    override x.ToString() = sprintf "%s: %d" x.field1 x.field2

Why would it work as a script but not compiled? I would like to keep it immutable if possible. Thanks for any insight!


Solution

  • FSI uses System.Reflection.Emit to compile your F# code on-the-fly. It appears that types generated with System.Reflection.Emit always have at least one constructor (either the default public constructor or an explicitly defined constructor). Thus it isn't easily possible for the code emitted by FSI to exactly imitate the result of the compiled code, which has no constructors at all (neither public nor private).