1

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!

4

1 に答える 1

1

FSI は System.Reflection.Emit を使用して、F# コードをオンザフライでコンパイルします。System.Reflection.Emit で生成された型には、常に少なくとも 1 つのコンストラクター (既定のパブリック コンストラクターまたは明示的に定義されたコンストラクター) があるようです。したがって、FSI によって発行されたコードが、コンストラクターをまったく持たない (パブリックでもプライベートでもない) コンパイルされたコードの結果を正確に模倣することは容易ではありません。

于 2012-01-27T18:45:23.990 に答える