为什么F#编译器在一种情况下给出错误,而在另一种情况下却没有给出错误? [英] Why does the F# compiler give an error for one case but not the other?

查看:60
本文介绍了为什么F#编译器在一种情况下给出错误,而在另一种情况下却没有给出错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从F#进行平台调用的工作中,并且遇到编译器错误,我实在无法理解.首先,让我展示我在做什么的C签名:

int Foo(
    ULONG_PTR *phHandle,
    DWORD flags
);

在F#中,我认为本地调用此代码的正确方法如下:

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

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

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

错误是:

类型实例化涉及一个byref类型.通用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

为什么将它编译为模块而不是类?

解决方案

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

如果您拉起 F#3.0语言规范并搜索DllImport,则底部附近是该表列出了一些特殊属性以及如何使用它们. [<DllImport>]的文本说:

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

这似乎表明仅在模块中定义的函数上声明extern方法(使用[<DllImport>])是有效的;它并没有说任何关于班级成员的事情.

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

I'm working on a platform invoke call from F#, and I am getting a compiler error I really can't make that much sense out of. First, let me show the C signature of what I am doing:

int Foo(
    ULONG_PTR *phHandle,
    DWORD flags
);

In F#, I think the correct way to invoke this natively is as so:

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

If I try to call this in a class, I get a compilation error when calling it like so:

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

The error is:

A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

Weirdly, when I do this all in a module, the compilation errors go away:

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

    let Foo() =
        let mutable thing = nativeint 0
        APlatformInvokeCall(&thing, 0u) |> ignore
        thing

Why does this compile as a module, but not as a class?

解决方案

I don't think it's valid to define an extern method within a class in F#.

If you pull up the F# 3.0 language specification and search for DllImport, near the bottom is a table listing some special attributes and how they can be used. The text for [<DllImport>] says:

When applied to a function definition in a module, causes the F# compiler to ignore the implementation of the definition, and instead compile it as a CLI P/Invoke stub declaration.

That seems to indicate that it's only valid to declare extern methods (that use [<DllImport>]) on functions defined in a module; it doesn't say anything about class members though.

I think you're running into a compiler bug. Please submit this code to fsbugs@microsoft.com so they can fix the error message emitted by the compiler -- it should really be giving you an error about defining an extern method in a class since that's not allowed by the language spec.

这篇关于为什么F#编译器在一种情况下给出错误,而在另一种情况下却没有给出错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆