为什么F#编译器会为一个案例而不是另一个案例给出错误?

vcs*_*nes 5 f#

我正在开发一个来自F#的平台调用调用,我收到一个编译器错误,我真的无法理解这一点.首先,让我展示我正在做的C签名:

int Foo(
    ULONG_PTR *phHandle,
    DWORD flags
);
Run Code Online (Sandbox Code Playgroud)

在F#中,我认为本机调用它的正确方法是这样的:

[<DllImport("somedll.dll")>]
static extern int APlatformInvokeCall
    (
        [<Out>]nativeint& phHandle,
        uint32 flags
    )
Run Code Online (Sandbox Code Playgroud)

如果我尝试在类中调用它,在调用它时会出现编译错误:

type Class1() = 
    [<DllImport("somedll.dll")>]
    static extern int APlatformInvokeCall
        (
            nativeint& phHandle,
            uint32 flags
        )

    member this.Foo() =
        let mutable thing = nativeint 0
        APlatformInvokeCall(&thing, 0u) |> ignore
        thing
Run Code Online (Sandbox Code Playgroud)

错误是:

类型实例化涉及byref类型.Common IL的规则不允许这样做.

奇怪的是,当我在一个模块中完成所有操作时,编译错误就会消失:

module Module1 = 
    [<DllImport("somedll.dll")>]
    extern int APlatformInvokeCall
        (
            nativeint& phHandle,
            uint32 flags
        )

    let Foo() =
        let mutable thing = nativeint 0
        APlatformInvokeCall(&thing, 0u) |> ignore
        thing
Run Code Online (Sandbox Code Playgroud)

为什么这个编译为模块,而不是作为一个类?

Jac*_* P. 2

extern我认为在 F# 中的类中定义方法是无效的。

如果您调出F# 3.0 语言规范并搜索DllImport,靠近底部的表格会列出一些特殊属性以及如何使用它们。文字[<DllImport>]说:

当应用于模块中的函数定义时,导致 F# 编译器忽略定义的实现,而是将其编译为 CLI P/Invoke 存根声明。

这似乎表明只有在模块中定义的函数上声明extern方法(使用)才有效;[<DllImport>]但它没有提及任何有关班级成员的信息。

我认为您遇到了编译器错误。请提交此代码,fsbugs@microsoft.com以便他们可以修复编译器发出的错误消息 - 它实际上应该给您一个有关extern在类中定义方法的错误,因为语言规范不允许这样做。