1

我编写了一个运行良好的 fsi 脚本,并希望对其进行编译,以便更轻松地移动它。但是,当我编译它时,突然 FileHelpers 开始报错。

以下代码使用FileHelpers 2.9.9。这是说明问题的最小工作示例,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")

文件test.csv

test1,1
test2,2
test3,3

如果我运行代码,fsi .\test.fsx它将正常工作。但是,如果我尝试编译fsc .\test.fsx并运行它,.\test.exe我会收到错误消息Unhandled Exception: FileHelpers.BadUsageException: The record class Type needs a constructor with no args (public or private)。在脚本和编译模式下工作的解决方法是

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

为什么它可以作为脚本工作而不是编译?如果可能的话,我想保持它不可变。感谢您的任何见解!

4

1 回答 1

1

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).

于 2012-01-27T18:45:23.990 回答